O comportamento de uma correspondência de padrão em um redirecionamento parece diferir entre os shells. Dentre os do meu sistema, dash e ksh93 não expandem o padrão, então você obtém um nome de arquivo com um literal *
. O Bash expande (1) , mas apenas se o padrão corresponder a um arquivo. Ele reclama se houver mais nomes de arquivos correspondentes. Zsh funciona como se você tivesse dado vários redirecionamentos, ele redireciona a saída para todos os arquivos correspondentes.
(1), exceto quando não é interativo e no modo POSIX
Se você deseja que a saída vá para todos os arquivos correspondentes, use tee
:
echo ... | tee /path/*/file > /dev/null
Se você quiser ir para apenas um arquivo, o problema é decidir qual deles usar. Se você quiser verificar se há apenas um arquivo que corresponda ao padrão, expanda a lista inteira e conte-os.
No bash / ksh:
names=(/path/*/file)
if [ "${#names[@]}" -gt 1 ] ; then
echo "there's more than one"
else
echo "there's only one: ${names[0]}"
fi
No shell padrão, set
dos parâmetros posicionais e use $#
para a contagem.
É claro que, se o padrão não corresponder a nenhum arquivo, ele ficará como está e, como o glob está no meio, o resultado aponta para um diretório inexistente. É o mesmo que tentar criar /path/to/file
, antes que /path/to
exista, é só aqui que temos /path/*
, literalmente, com o asterisco.
Para lidar com isso, você teria que expandir o (s) nome (s) do diretório sem o nome do arquivo e, em seguida, acrescentar o nome do arquivo a todos os diretórios. Isso é um pouco feio ...
dirs=(/path/*)
files=( "${dirs[@]/%/\/file}" )
e depois podemos usar esse array:
echo ... | tee "${files[@]}" > /dev/null
Ou podemos pegar o caminho mais fácil e percorrer o padrão do nome do arquivo. É um pouco insatisfatório no caso mais geral, já que requer a execução do comando principal uma vez para cada arquivo de saída ou o uso de um arquivo temporário para manter a saída.
for dir in /path/* ; do
echo ... > "$dir/file"
done