Проблема здесь в том, что в конвейере cat "$filename" | wc -l
, когда файл не существует, cat
выйдет с ошибкой, но wc -l
успешно посчитает 0 строк текста, полученных от cat
. Состояние выхода последней команды в конвейере рассматривается как окончательное состояние конвейера в целом, поэтому весь конвейер считается успешным. Как это:
$ cat nosuchfile | wc -l
cat: nosuchfile: No such file or directory
0
$ echo "$?"
0
Обычно в bash вы можете получить статусы отдельной команды в конвейере с массивом PIPESTATUS
, например:
$ cat nosuchfile | wc -l
cat: nosuchfile: No such file or directory
0
$ echo "${PIPESTATUS[@]}"
1 0
... но это не работает с конвейером в расширении команды, таком как $( )
, потому что этот конвейер будет выполняться в подоболочке, а PIPESTATUS
не может распространяться из подоболочки; только окончательный статус передается обратно в родительскую оболочку:
$ line_count=$(cat nosuchfile | wc -l)
cat: nosuchfile: No such file or directory
$ echo "${PIPESTATUS[@]}"
0
Итак, что вы можете сделать по этому поводу? Ну, как сказал l0b0, одна возможность - установить pipefail
. Вам не нужно делать это для всего сценария, вы можете установить его только для этой конкретной подоболочки, выполнив это в подстановке команд:
$ line_count=$(set -o pipefail; cat nosuchfile | wc -l)
cat: nosuchfile: No such file or directory
$ echo "$?"
1
Для этой конкретной команды вы также можете исключить конвейер (это то, что называется бесполезным использованием cat или UUOC), и иметь wc
чтения непосредственно из файла, либо передавая имя файла в качестве параметра:
$ line_count=$(wc -l nosuchfile)
wc: nosuchfile: open: No such file or directory
$ echo $?
1
... или используя перенаправление ввода:
$ line_count=$(wc -l <nosuchfile)
-bash: nosuchfile: No such file or directory
$ echo $?
1
Есть несколько различий между этими двумя параметрами: если вы передадите имя файла в wc
(и оно существует), оно выведет имя файла, а также количество строк:
$ line_count=$(wc -l realfile.txt)
$ echo "$line_count"
6 realfile.txt
... в то время как с опцией перенаправления не будет. Кроме того, со вторым параметром оболочка отвечает за открытие файла (и передачу дескриптора открытого файла команде wc
), поэтому в случае неудачи именно оболочка выдает ошибку (обратите внимание, что сообщение об ошибке исходит от «-bash» , а не wc
) и wc
никогда не запускается.