В чем смысл! # (Bang-фунт) в оболочке sh/Bash script?

Я хочу понять, как работает этот Scala script:

#!/usr/bin/env bash
exec scala "$0" "[email protected]"
!#
object HelloWorld {
    def main(args: Array[String]) {
        println("Hello, world! " + args.toList)
    }   
}
HelloWorld main args

В строке 3, что делает "! #"? Остается ли остаток файла в стандартный ввод программы Scala? Кроме того, "! #" Документирован где угодно?

NB: Самое ближайшее, что я мог найти, хотя это не имеет прямого отношения к вопросу о переполнении стека Зачем вам нужно поставить #!/bin/ bash в начало файла script? (о начале Bash script).

Ответ 1

Из исходная документация:

Script файлы могут иметь необязательный заголовок, который игнорируется, если он присутствует. Существует два способа форматирования заголовка: либо С#! и заканчивается на! #, или начиная с:: #! и заканчивается на::! #.

Итак, следующий код - это просто заголовок для Scala script:

#!/usr/bin/env bash
exec scala "$0" "[email protected]"
!#

Ответ 2

Когда я удалил !# в образце программы в ответ BluesRockAddict, я получаю следующую ошибку на консоли:

ошибка: script файл не закрывает свой заголовок с помощью! # или::! # обнаружена одна ошибка

Из приведенного выше сообщения об ошибке я понял следующие вещи:

  • !# - тег close для заголовка exec scala "$0" "[email protected]", который, вероятно, сообщает Scala, что все, что приходит после !#, - это код Scala, который должен быть выполнен.
  • !# можно заменить на ::!#.

Ответ 3

Основываясь исключительно на экспериментировании (я предполагаю, что это описано где-то):

Начиная с Scala 2.10.0, нестандартный (из POSIX скриптовый POV) фунт-бит (! #) больше не требуется (или разрешается) в среде оболочки POSIX. Следующая одиночная строка работает (но должна быть первой строкой script без начальных пробелов):

#!/usr/bin/env scala

Однако единственный способ предоставить shebang в пакетном файле Windows - обмануть его при вызове Scala с самим собой в качестве первого аргумента. Следовательно, Scala должен знать, где находится последняя строка командного файла, и поэтому требует закрытие::! # Строки. Вот рабочий пример:

::#!
call scala %0 %*
goto :eof
::!#

Исправление: у меня изначально было #!/usr/bin/env scalav (обратите внимание на trailing v), который является моим script для определения свойства "scala.script", добавьте некоторые библиотеки в путь к классам, exec scala '. Таким образом, можно определить имя выполняемого script, хотя scalav должен быть в вашем PATH.