Você também pode usar o find em um subprocesso e alimentar a saída para cat:)
cat $(find . -name "*.tcl")
Em um esforço para aprender melhor o shell e sem precisar recorrer aos xargs, tenho tentado descobrir outras maneiras de fazer:
find . -name *.tcl | xargs -I{} cat {}
Os xargs fazem com que pareça confuso e eu gostaria de saber se há várias maneiras de fazer isso.
EDITAR: Eu descobri que outra solução é usar:
find . -name "*.tcl" | cat 'cat /dev/stdin'
Eu não entendo porque eu tenho que catar um nome de arquivo antes que cat o veja como um arquivo em vez de uma string ...
Você pode usar exec in find:
find . -name "*.tcl" -exec cat {} \;
Tudo entre o -exec
e o trailing \;
é o comando a ser executado. Como xargs, você substitui os resultados da pesquisa por {}. Para cada arquivo que é encontrado, o cat é executado (da mesma forma que o xargs faz a iteração na lista de arquivos fornecidos via STDIN.
Alguns podem argumentar que isso é mais eficiente, já que você não está usando um pipe ou iniciando outro aplicativo.
Se você usa bash
, apenas:
shopt -s globstar # to match files recursively
cat -- **/*.tcl
Você pode executar um comando para cada linha da entrada com um loop while
e o comando interno do shell read
:
find . -name '*.tcl' | while IFS= read -r filename; do cat "$filename"; done
Para simplificar, minha preferência por isso seria a solução limpa e legível já apresentada por Mark Komarinski . No entanto, existem muitas maneiras de fazer isso no Bash. Outra maneira interessante é evitar cat
e aproveitar o redirecionamento:
find . -name '*.tcl' -exec sh -c 'printf "%s\n" "$(< {})' \;;
Na verdade, se você quiser realizar toda a tarefa exclusivamente com os recursos internos do Bash, poderá combinar o uso do redirecionamento com solução glob colocada pelo caos :
shopt_globstar_temp="$(shopt -p globstar)";
shopt -s globstar;
for filename in **/*.bat; do
printf "%s" "$(< "${filename}")";
done;
${shopt_globstar_temp};
Estes são um pouco confusos, mas meu ponto aqui é ilustrar que o Bash pode fazer alguns poderosos coisas com descritores de arquivos e redirecionamento . Muitas vezes há muitas soluções para um determinado problema.
I don't understand why I have to cat a filename before cat will see it as a file instead of a string though....
A saída de cat /dev/fd/stdin
será a mesma que a saída de find
em seu último exemplo, então será efetivamente substituída por <filename1>.tcl <filename2>.tcl ...
e cat
usar essa lista de arquivos como sua lista de argumentos. / p>
Se você está se perguntando por que você tem que cat stdin
no mesmo exemplo, a razão é que nem todos os programas tratam stdin
da mesma forma que tratam argumentos. Se os dados forem transferidos para cat
a stdin
, então cat
simplesmente produzirá os mesmos dados em vez de interpretá-los como um nome de arquivo a ser lido.