Как лучше (идиоматически) завершить работу сценария Perl (запускается с -n / -p), если входной файл не найден?

11
$ perl -pe 1 foo && echo ok
Can't open foo: No such file or directory.
ok

Мне бы очень хотелось, чтобы скрипт perl не работал, когда файл не существует. Что такое «правильный» способ заставить -p или -n завершиться ошибкой, когда входной файл не существует?

Уильям Перселл
источник

Ответы:

6

Ключ -p это просто ярлык для упаковки вашего кода (аргумент следующего -e) в этом цикле:

LINE:
  while (<>) {
      ...             # your program goes here
  } continue {
      print or die "-p destination: $!\n";
  }

(-n то же самое, но без блока продолжения.)

<>Пустой оператор эквивалентен readline *ARGV, и который открывает каждый аргумент в последовательности в виде файла на чтение. Нет никакого способа повлиять на обработку ошибок этого неявного открытия, но вы можете сделать предупреждение, которое оно генерирует, фатальным (обратите внимание, это также повлияет на несколько предупреждений, связанных с ключом -i):

perl -Mwarnings=FATAL,inplace -pe 1 foo && echo ok
Grinnz
источник
@MarkReed inplace - это интересующая нас категория предупреждений. Нет причин влиять на другие предупреждения.
Гриннц
Из предупреждений :The presence of the word "FATAL" in the category list will escalate warnings in those categories into fatal errors in that lexical scope.
Гриннц
Правильно, inplaceэто категория; без этого -Mwarnings=FATALсредства FATAL => all, которые мы не хотим. понял.
Марк Рид
4

Установите флаг в теле цикла, проверьте флаг в блоке END в конце oneliner.

perl -pe '$found = 1; ... ;END {die "No file found" unless $found}' -- file1 file2

Обратите внимание, что это происходит только когда файл не был обработан.

Чтобы сообщить о проблеме, когда не все файлы были найдены, вы можете использовать что-то вроде

perl -pe 'BEGIN{ $files = @ARGV} $found++ if eof; ... ;END {die "Some files not found" unless $files == $found}'
choroba
источник
1
Если ваш сценарий должен принимать файлы в качестве аргументов, а не читать их из stdin, более легкой альтернативой этому решению будет BEGIN{die "File not found" unless -f $ARGV[0]}. (Я говорю легче, потому что это не требует установки флага и добавления 2-х частей кода)
Дада
Также предполагается, что все файлы имеют ненулевую длину.
Tanktalus