Atualização 2020 para usuários Linux:
Se você tem uma versão atualizada do bash (4.4-alpha ou melhor), como provavelmente tem se estiver no Linux, então você deve usar a resposta de Benjamin W ..
Se você estiver no Mac OS, que - pelo menos eu verifiquei - ainda usava o bash 3.2 ou, de outra forma, está usando um bash mais antigo, continue na próxima seção.
Resposta para bash 4.3 ou anterior
Aqui está uma solução para obter a saída de find
em uma bash
matriz:
array=()
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done < <(find . -name "${input}" -print0)
Isso é complicado porque, em geral, os nomes dos arquivos podem ter espaços, novas linhas e outros caracteres hostis ao script. A única maneira de usar find
e ter os nomes dos arquivos separados uns dos outros com segurança é usar o -print0
que imprime os nomes dos arquivos separados por um caractere nulo. Isso não seria muito inconveniente se as funções readarray
/ do bash mapfile
suportassem strings separadas por nulos, mas não o fazem. O de Bash read
sim e isso nos leva ao loop acima.
[Esta resposta foi escrita originalmente em 2014. Se você tiver uma versão recente do bash, consulte a atualização abaixo.]
Como funciona
A primeira linha cria uma matriz vazia: array=()
Cada vez que a read
instrução é executada, um nome de arquivo separado por nulo é lido da entrada padrão. A -r
opção diz read
para deixar os caracteres de barra invertida sozinhos. O -d $'\0'
informa read
que a entrada será separada por nulos. Desde que omitir o nome para read
, a concha coloca a entrada para o nome padrão: REPLY
.
A array+=("$REPLY")
instrução anexa o novo nome do arquivo ao array array
.
A linha final combina redirecionamento e substituição de comando para fornecer a saída find
para a entrada padrão do while
loop.
Por que usar a substituição de processo?
Se não usássemos a substituição de processo, o loop poderia ser escrito como:
array=()
find . -name "${input}" -print0 >tmpfile
while IFS= read -r -d $'\0'; do
array+=("$REPLY")
done <tmpfile
rm -f tmpfile
Acima, a saída de find
é armazenada em um arquivo temporário e esse arquivo é usado como entrada padrão para o loop while. A ideia da substituição do processo é tornar esses arquivos temporários desnecessários. Portanto, em vez de fazer com que o while
loop obtenha seu stdin tmpfile
, podemos fazer com que ele obtenha seu stdin de <(find . -name ${input} -print0)
.
A substituição de processos é amplamente útil. Em muitos lugares onde um comando deseja ler de um arquivo, você pode especificar a substituição de processo,, em <(...)
vez de um nome de arquivo. Há uma forma análoga,, >(...)
que pode ser usada no lugar do nome do arquivo onde o comando deseja gravar no arquivo.
Como os arrays, a substituição de processos é um recurso do bash e de outros shells avançados. Não faz parte do padrão POSIX.
Alternativa: lastpipe
Se desejado, lastpipe
pode ser usado em vez de substituição de processo (gorjeta: César ):
set +m
shopt -s lastpipe
array=()
find . -name "${input}" -print0 | while IFS= read -r -d $'\0'; do array+=("$REPLY"); done; declare -p array
shopt -s lastpipe
diz ao bash para executar o último comando no pipeline no shell atual (não no fundo). Dessa forma, o array
permanece após a conclusão do pipeline. Porque lastpipe
só tem efeito se o controle de trabalho estiver desativado, nós corremos set +m
. (Em um script, ao contrário da linha de comando, o controle de tarefas está desativado por padrão.)
Notas Adicionais
O comando a seguir cria uma variável de shell, não uma matriz de shell:
array=`find . -name "${input}"`
Se você quiser criar uma matriz, precisará colocar parênteses ao redor da saída de find. Então, ingenuamente, pode-se:
array=(`find . -name "${input}"`)
O problema é que o shell executa a divisão de palavras nos resultados de, de find
modo que os elementos do array não são garantidos como sendo o que você deseja.
Atualização 2019
A partir da versão 4.4-alpha, o bash agora suporta uma -d
opção para que o loop acima não seja mais necessário. Em vez disso, pode-se usar:
mapfile -d $'\0' array < <(find . -name "${input}" -print0)
Para mais informações sobre este assunto, consulte (e upvote) a resposta de Benjamin W. .