Como faço para catar um arquivo que recebi de stdin sem xargs

2

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 ...

    
por Josh Barton 28.10.2015 / 18:50

5 respostas

1

Você também pode usar o find em um subprocesso e alimentar a saída para cat:)

cat $(find . -name "*.tcl")
    
por 28.10.2015 / 20:11
2

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.

    
por 28.10.2015 / 18:58
2

Se você usa bash , apenas:

shopt -s globstar # to match files recursively
cat -- **/*.tcl
    
por 28.10.2015 / 19:00
1

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
    
por 28.10.2015 / 22:59
1

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.

    
por 29.10.2015 / 01:24