Bash - разница между < - PullRequest
       1

Bash - разница между <

1 голос
/ 07 мая 2020

GNU Bash - 3.6.6 Здесь Документы

[n]<<[-]word
        here-document
delimiter

Если какая-либо часть слова заключена в кавычки , разделитель является результатом удаления кавычек на слове, и строки в документе не расширяются. Если слово не заключено в кавычки, все строки здесь-документа подвергаются расширению параметров, подстановке команд и расширению арифметики c, последовательность символов \ новая строка игнорируется, и '\' необходимо использовать для заключения в кавычки символов '\' , '$' и '' '.

Если я заключу EOF в одинарные кавычки, это сработает. Я думаю, потому что вызываемый процесс bash / bin / bash получает нераскрытые строки, а затем вызываемый процесс интерпретирует строки.

$ /bin/bash<<'EOF'
#!/bin/bash
echo $BASH_VERSION
EOF               
3.2.57(1)-release

Однако ниже вызывает ошибку. Я думал, что BASH_VERSION был бы расширен, и версия текущего процесса bash передается в процесс / bin / bash для вызова. Но не работает.

$ /bin/bash<<EOF 
#!/bin/bash
echo $BASH_VERSION
EOF               
/bin/bash: line 2: syntax error near unexpected token `('
/bin/bash: line 2: `echo 5.0.17(1)-release'

Ответы [ 3 ]

4 голосов
/ 07 мая 2020
/bin/bash<<EOF 
#!/bin/bash
echo $BASH_VERSION
EOF

Как вы можете заключить из сообщения об ошибке, heredo c расширяется до:

/bin/bash<<EOF 
#!/bin/bash
echo 5.0.17(1)-release
EOF

Похоже, это то, что вы ожидаете: это расширен до версии внешней оболочки. Проблема не в heredo c или расширении; Дело в том, что круглые скобки без кавычек являются синтаксической ошибкой. Попробуйте запустить вручную команду echo, и вы получите ту же ошибку:

$ echo 5.0.17(1)-release
bash: syntax error near unexpected token `('

Чтобы исправить это, вы можете добавить дополнительные кавычки:

/bin/bash<<EOF 
echo '$BASH_VERSION'
EOF

Это будет работать и распечатайте версию внешней оболочки. Я использовал одинарные кавычки, чтобы продемонстрировать, что эти кавычки не будут препятствовать расширению переменных. Внешняя оболочка не видит этих кавычек. Только внутренняя оболочка.

(Я также избавился от строки #!/bin/bash shebang. В этом нет необходимости, поскольку вы явно вызываете bash.)

Однако цитирование не является 100% надежным. Если $BASH_VERSION содержит одинарные кавычки, у вас возникнут проблемы. Кавычки делают скобки ( ) безопасными, но они не надежны. В качестве общей техники, если вы хотите, чтобы это было полностью безопасно независимо от того, какие специальные символы находятся в игре , вам придется прыгать через некоторые уродливые обручи.

  1. Используйте printf '%q', чтобы экранировать все специальные символы.

    /bin/bash <<EOF
    echo $(printf '%q' "$BASH_VERSION")
    EOF
    

    Это будет расширено до echo 5.0.17\(1\)-release.

  2. Передайте его как переменную среды и используйте <<'EOF' чтобы отключить интерполяцию внутри скрипта.

    OUTER_VERSION="$BASH_VERSION" /bin/bash <<'EOF'
    echo "$OUTER_VERSION"
    EOF
    

    Это был бы мой выбор. По возможности я предпочитаю использовать форму <<'EOF'. Если родительская оболочка интерполирует скрипт, передаваемый дочерней оболочке, это может сбивать с толку и вызывать затруднения. Кроме того, явная переменная $OUTER_VERSION проясняет, что происходит.

  3. Используйте bash -c 'script' вместо heredo c, а затем передайте версию в качестве аргумента командной строки .

    bash -c 'echo "$1"' bash "$BASH_VERSION"
    

    Я мог бы go с этим для однострочного скрипта.

0 голосов
/ 07 мая 2020

В первом случае кавычки предотвращают любые изменения в документе здесь, поэтому суб-оболочка видит echo $BASH_VERSION, расширяет строку и повторяет ее.

Во втором случае отсутствие кавычки означают, что первая оболочка расширяет информацию и видит echo 3.2.57(1)-release, и если вы введете это в командной строке, вы получите синтаксическую ошибку.

Если вы использовали echo "$BASH_VERSION" в обоих, то оба работают, но другие оболочки будут расширяться $BASH_VERSION.

0 голосов
/ 07 мая 2020

Если вы не цитируете EOF, переменные в heredo c расширяются исходной оболочкой перед передачей ее в качестве входных данных вызываемой оболочке. Таким образом, это эквивалентно выполнению

echo 3.2.57(1)-release

в вызванной оболочке. Это недопустимый синтаксис bash, поэтому вы получите ошибку.

Цитирование слова предотвращает расширение переменной, поэтому вызываемая оболочка получает $BASH_VERSION буквально и расширяет его сама.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...