Проблема с зависанием с подстановочным знаком в сценарии bash

Я новичок в написании bash-скриптов. Этот вопрос, вероятно, очень простой, но я пока не смог найти четкого ответа. Я работаю над установкой подсистемы Ubuntu в Windows 10.

Я запускаю скрипт, который содержит следующее условие:

if [ -z "$date1" ]; then
    date1=$(head -n 1 "$dir"/*.txt | sed "s/^[^0-9]*//g" | date +%Y%m%d -f - 2>/dev/null)
fi

У него возникают проблемы, когда он сталкивается с каталогом (переменная dir), в котором нет файла .txt, но я не совсем понимаю природу проблемы. Я знаю, что проблема в команде head, по крайней мере частично. Я не получаю ошибку, сценарий просто останавливается, когда достигает каталога без файла .txt. Я хочу, чтобы сценарий просто двигался дальше. Если я запускаю строку отдельно (без условного выражения) в терминале, я получаю ошибку No such file or directory, что имеет смысл. Что меня действительно смущает, так это то, что если я помещаю кавычки (одинарные или двойные) вокруг части подстановочного знака (например, '*.txt'), то скрипт выдает ошибку head и движется дальше. Мое ограниченное и, возможно, неправильное понимание состоит в том, что кавычки в данном случае означают, что программа больше не рассматривает * как подстановочный знак и просто ищет файл с буквальным именем *.txt. Но я думал, что когда bash интерпретирует *, он сначала ищет любое возможное расширение, а затем пробует буквальную интерпретацию, если не находит ничего. Так почему же скрипт зависает в одном случае, а не в другом. Разве оба не должны просто выдавать ту же ошибку No such file or directory, что и при запуске вне сценария?

Я также упомяну, что сценарий включает в себя предыдущие условия, которые сначала ищут файлы .docx и переходят к файлам .txt только тогда, когда файлов .docx нет. Он отлично справляется со случаями, когда файлы .docx отсутствуют, хотя первая команда в этом канале — unzip, а не head. Этот вопрос кажется актуальным, но поскольку скрипт может двигаться дальше когда вокруг подстановочного знака есть кавычки, и поскольку он движется по аналогичному сценарию, где нет файлов .docx, я хотел понять, в чем здесь проблема, и как ее исправить.

Я ценю вашу помощь.


person Archimedes    schedule 03.03.2021    source источник
comment
Может быть, вы включили nullglob в своем скрипте? Это объясняет задержку. Проверьте состояние nullglob в этом месте скрипта с помощью shopt nullglob.   -  person user1934428    schedule 03.03.2021


Ответы (1)


В кавычках * не будет расширяться и будет буквальным символом *.

С другой стороны, когда * пытается расшириться и терпит неудачу, происходит одно из трех:

  • it is interpreted literally as the string *.txt (plus whatever $dir/ expands to)
    • You can enforce this behavior with shopt -u nullglob, which should be the default.
  • it expands to nothing, making the string $dir/*.txt equal to the empty string
    • You can enforce this behavior with shopt -s nullglob.
  • it raises an error
    • You can enforce this behavior with shopt -s failglob (or turn it off with shopt -u failglob).

Примеры:

bash-5.0# shopt -s | grep glob
globasciiranges on
bash-5.0# echo *.asdf
*.asdf
bash-5.0# shopt -s nullglob
bash-5.0# echo *.asdf

bash-5.0# shopt -u nullglob
bash-5.0# echo *.asdf
*.asdf
bash-5.0# shopt -s failglob
bash-5.0# echo *.asdf
bash: no match: *.asdf
bash-5.0# shopt -s | grep glob
failglob        on
globasciiranges on

Когда glob расширяется до пустой строки, head будет зависать навсегда, если вы не введете стандартный ввод (head $(echo '') | cat никогда не завершится, пока вы не наберете)

person jeremysprofile    schedule 03.03.2021
comment
Итак, судя по симптому, похоже, что скрипт запустился shopt -s nullglob, и это вызывает проблему. - person Gordon Davisson; 03.03.2021
comment
У меня действительно было shopt -s nullglob в сценарии, и, честно говоря, я уже не помню, почему. Ясно, что у меня не было адекватного понимания того, что он делал. Теперь это имеет большой смысл. Спасибо всем за вашу помощь и @jeremysprofile за подробный разбор. Это, безусловно, послужит мне в будущем. - person Archimedes; 03.03.2021