Использование 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
один раз для каждого файла.
Вы используете не регулярные выражения, а комбинацию расширения скобок и расширения имени файла (, также известного как подстановка). Это важно, потому что в то время как раскрытие фигурных скобок просто расширяет строку, содержащую конструкцию {... }
, в несколько разных строк, подстановочная часть фактически пытается сопоставить существующие файлы с шаблоном . Вот в чем проблема (Кстати, даже регулярные выражения используются для сопоставления существующей строки с шаблоном , а не для генерации строки по шаблону ).
В частности, обратите внимание, что раскрытие фигурных скобок выполняется перед раскрытием имени файла.
Так
file{[1-9],1[0-9],20}.txt
расширяется оболочкой в три символа, разделенные пробелом -
file[1-9].txt file1[0-9].txt file20.txt
, которые затем подвергаются фактическому расширению имени файла, в котором оболочка проверяет, какие из существующих файлов соответствуют этому шаблону глобуса . Важно то, что если ни один файл не соответствует одному из шаблонов, шаблоны воспринимаются буквально .
Итак, в случае вашего открытия происходит следующее
vim file{[1-9],1[0-9],20}.txt
расширяется доvim file[1-9].txt file1[0-9].txt file20.txt
vim file[1-9].txt file1[0-9].txt file20.txt
расширяется до vim file1.txt file2.txt... file20.txt
, потому что все эти файлы существуют(он не будет не расширен до любых не -существующих файлов в этом диапазоне номеров)vim
открывает все эти файлы. Однако при использовании, например,. touch
с теми же аргументами для создания не -существующих файлов , что происходит
touch file{[1-9],1[0-9],20}.txt
расширяется доtouch file[1-9].txt file1[0-9].txt file20.txt
[1-9]
, 1[0-9]
и 20
остаются буквально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
, который выдает ошибку вместо выполнения команды, если есть глобус, который ничему не соответствует.