Проблема здесь в том, что в конвейере 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 никогда не запускается.