O problema aqui é que no pipeline cat "$filename" | wc -l
, quando o arquivo não existir, cat
sairá com um erro, mas wc -l
contará com êxito as 0 linhas de texto que recebe de cat
. O status de saída do último comando no pipeline é tratado como o status final do pipeline como um todo, portanto, todo o pipeline é considerado bem-sucedido. Assim:
$ cat nosuchfile | wc -l
cat: nosuchfile: No such file or directory
0
$ echo "$?"
0
Normalmente, no bash, você pode obter os status do comando individual em um pipeline com a matriz PIPESTATUS
, assim:
$ cat nosuchfile | wc -l
cat: nosuchfile: No such file or directory
0
$ echo "${PIPESTATUS[@]}"
1 0
... mas isso não funciona com um pipeline em uma expansão de comando como $( )
, porque esse pipeline será executado em uma subshell e PIPESTATUS
não poderá se propagar a partir da subshell; somente o status final é passado de volta para o shell pai:
$ line_count=$(cat nosuchfile | wc -l)
cat: nosuchfile: No such file or directory
$ echo "${PIPESTATUS[@]}"
0
Então, o que você pode fazer sobre isso? Bem, como disse o l0b0, uma possibilidade é definir a opção pipefail
. Você não precisa fazer isso para o script inteiro, você pode configurá-lo apenas para essa sub-rotina em particular, fazendo isso dentro da substituição do comando:
$ line_count=$(set -o pipefail; cat nosuchfile | wc -l)
cat: nosuchfile: No such file or directory
$ echo "$?"
1
Para esse comando específico, você também pode eliminar o pipeline (o que é chamado de Uso inútil de cat, ou UUOC ), e ter wc
lido diretamente do arquivo, passando o nome do arquivo como parâmetro:
$ line_count=$(wc -l nosuchfile)
wc: nosuchfile: open: No such file or directory
$ echo $?
1
... ou usando um redirecionamento de entrada:
$ line_count=$(wc -l <nosuchfile)
-bash: nosuchfile: No such file or directory
$ echo $?
1
Existem algumas diferenças entre essas duas opções: se você passar o nome do arquivo para wc
(e ele existir), ele exibirá o nome do arquivo e o número de linhas:
$ line_count=$(wc -l realfile.txt)
$ echo "$line_count"
6 realfile.txt
... enquanto com a opção de redirecionamento não. Além disso, com a segunda opção, o shell é responsável por abrir o arquivo (e entregar o identificador de arquivo aberto ao comando wc
), portanto, se ele falhar, é o shell que fornece um erro (observe que a mensagem de erro é "- bash ", não wc
) e wc
nunca são executados.