Асимметрия расширения Bash при открытии и создании файлов

Использование GNUawk:

$ awk 'ENDFILE { if ($0 !~ /must have/) print FILENAME }' file2.txt file1.txt
file2.txt

Здесь используется блок ENDFILEдля проверки текущего содержимого$0(последней строки файла, до которого мы только что дошли до конца )относительно регулярного выражения must have. Если совпадений нет, печатается имя файла.

Блок ENDFILEнедоступен в BSD awkили mawk.

Использование стандартаawk:

for fname in *.txt; do
    awk 'END { if ($0 !~ /must have/) print FILENAME }' "$fname"
done

Это работает аналогично решению GNU awk, но вызывает awkодин раз для каждого файла.

6
25.02.2021, 16:49
1 ответ

Вы используете не регулярные выражения, а комбинацию расширения скобок и расширения имени файла (, также известного как подстановка). Это важно, потому что в то время как раскрытие фигурных скобок просто расширяет строку, содержащую конструкцию {... }, в несколько разных строк, подстановочная часть фактически пытается сопоставить существующие файлы с шаблоном . Вот в чем проблема (Кстати, даже регулярные выражения используются для сопоставления существующей строки с шаблоном , а не для генерации строки по шаблону ).

В частности, обратите внимание, что раскрытие фигурных скобок выполняется перед раскрытием имени файла.

Так

file{[1-9],1[0-9],20}.txt

расширяется оболочкой в ​​три символа, разделенные пробелом -

file[1-9].txt file1[0-9].txt file20.txt

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

Итак, в случае вашего открытия происходит следующее

  1. vim file{[1-9],1[0-9],20}.txtрасширяется доvim file[1-9].txt file1[0-9].txt file20.txt
  2. vim file[1-9].txt file1[0-9].txt file20.txtрасширяется до vim file1.txt file2.txt... file20.txt, потому что все эти файлы существуют(он не будет не расширен до любых не -существующих файлов в этом диапазоне номеров)
  3. vimоткрывает все эти файлы.

Однако при использовании, например,. touchс теми же аргументами для создания не -существующих файлов , что происходит

  1. touch file{[1-9],1[0-9],20}.txtрасширяется доtouch file[1-9].txt file1[0-9].txt file20.txt
  2. Поскольку ни один файл не соответствует этому шаблону, [1-9], 1[0-9]и 20остаются буквально
  3. touchсоздает эти три файла с именами, воспринимаемыми буквально.

Если вы хотите избежать этого, и поскольку вы хотите создать все файлы в этом диапазоне, вы можете просто ограничить строку команды -расширением фигурной скобки, т.е.

touch file{1..20}.txt

(, как также отмечено в комментарии pLumo)


В качестве примечания (, предложенного @Quasimodo ), в bashи многих других оболочках поведение подстановки можно настроить с помощью параметров оболочки , в bash, специально используя shopt -s option.

Здесь, в частности, интересна опция nullglob, поскольку она заставит оболочку расширять шаблон подстановки, который не соответствует ни одному имени файла, в пустую строку, вместо того, чтобы буквально сохранять шаблон в ней. Это особенно полезно, если вы хотите перебрать все файлы, соответствующие шаблону, используя цикл for:

.
  • Без опции nullglobпетля вида
    for f in *.txt
    
    будет выполняться ровно один раз с $f, установленным в литерал *.txt, если в текущем каталоге нет .txt, что может привести к непредвиденному поведению (, т.е. коду, пытающемуся работать с не -существующий файл)
  • С опцией nullglobоболочка вообще не попадала в тело цикла.

С другой стороны (, как правильно заметил @Barmar ), многие программы, работающие с файлами, будут молча пытаться читать из stdin, если вы предоставите им шаблон глобуса, который оценивается как «ничего», потому что никакие имена файлов не совпадают, поэтому использование этой опции может иметь странные побочные -эффекты, если вы не будете осторожны.

Кроме того nullglob, Bash имеет параметр failglob, который выдает ошибку вместо выполнения команды, если есть глобус, который ничему не соответствует.

18
18.03.2021, 22:28

Теги

Похожие вопросы