Bash: canaliza 'encontrar' saída para 'readarray'


14

Estou tentando procurar arquivos usando find, e colocar esses arquivos em uma matriz Bash para que eu possa fazer outras operações sobre eles (por exemplo, lsou grepeles). Mas não consigo entender por que readarraynão está lendo a findsaída, pois ela é canalizada para ela.

Digamos que eu tenha dois arquivos no diretório atual file1.txte file2.txt. Portanto, a findsaída é a seguinte:

$ find . -name "file*"
./file1.txt
./file2.txt

Então, eu quero colocar isso em uma matriz cujos dois elementos são as strings "./file1.txt"e "./file2.txt"(sem aspas, obviamente).

Eu tentei isso, entre algumas outras coisas:

$ declare -a FILES
$ find . -name "file*" | readarray FILES
$ echo "${FILES[@]}"; echo "${#FILES[@]}"

0

Como você pode ver na echosaída, minha matriz está vazia.

Então, o que exatamente estou fazendo de errado aqui? Por que a saída da readarrayleitura não é findsua entrada padrão e coloca essas strings na matriz?

Respostas:


21

Ao usar um pipeline, o bash executa os comandos em subshells. Portanto, a matriz é preenchida, mas em um subshell, para que o shell pai não tenha acesso a ela.

Use substituição de processo:

readarray FILES < <(find)

Observe que ele não funciona para arquivos com novas linhas em seus nomes. Se for esse o caso, você precisa de uma sintaxe mais elaborada:

readarray -d '' < <(find -print0)

3
Para dar suporte às novas linhas, isso é suficiente:readarray -d '' < <(find your_args -print0)
VasyaNovikov 18/01/18

6

A solução correta é:

unset a; declare -a a
while IFS= read -r -u3 -d $'\0' file; do
    a+=( "$file" )        # or however you want to process each file
done 3< <(find /tmp -type f -print0)

Isso é semelhante ao que o BashFAQ 020 de Greg explica em detalhes e esta resposta abrange .

Não tem problema com arquivos nomeados ímpares (que não contêm NUL no nome), com espaços ou novas linhas. E o resultado é definido em uma matriz, o que o torna útil para processamento adicional.


Ótimo, esta é uma solução melhor para o problema que eu estava tentando resolver em primeiro lugar. +1 assim que meu representante atinge 15 :)
villapx

3

readarray também pode ler de stdin

readarray FILES <<< "$(find . -name "file*")"; echo "${#FILES[@]}"

Isso não funciona com find -print0a proteção contra nomes de arquivos "inesperados".
roaima
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.