O comando find no Linux é ótimo para pesquisar arquivos e diretórios. Mas você também pode passar os resultados da pesquisa para outros programas para processamento posterior. Nós mostramos-lhe como.
O comando find do Linux
O comando Linux find
é poderoso e flexível. Ele pode pesquisar arquivos e diretórios usando uma série de critérios diferentes, não apenas nomes de arquivos. Por exemplo, ele pode pesquisar arquivos vazios, arquivos executáveis ou arquivos pertencentes a um usuário específico.
Ele pode encontrar e listar arquivos por seus horários acessados ou modificados, você pode usar padrões regex, é recursivo por padrão e funciona com pseudo-arquivos como pipes nomeados (buffers FIFO).
Tudo isso é fantasticamente útil. O comando humilde find
realmente tem algum poder. Mas há uma maneira de alavancar esse poder e levar as coisas para outro nível. Se pudermos pegar a saída do comando find
e usá-la automaticamente como entrada de outros comandos, podemos fazer algo acontecer com os arquivos e diretórios que encontram descobertas para nós.
O princípio de canalizar a saída de um comando para outro comando é uma característica central dos sistemas operacionais derivados do Unix. O princípio de design de fazer um programa fazer uma coisa e fazê-lo bem, e esperar que sua saída possa ser a entrada de outro programa – mesmo um programa ainda não escrito – é frequentemente descrito como a “filosofia Unix”. E, no entanto, alguns utilitários principais, como mkdir
, não aceitam entrada canalizada.
Para resolver essa deficiência , o comando xargs
pode ser usado para dividir a entrada canalizada e alimentá-la em outros comandos como se fossem parâmetros de linha de comando para esse comando. Isso alcança quase a mesma coisa que a tubulação simples. Isso é “quase a mesma coisa”, e não “exatamente a mesma coisa”, porque pode haver diferenças inesperadas com expansões de shell e globbing de nome de arquivo.
Usando find Com xargs
Podemos usar find
com xargs
alguma ação realizada nos arquivos que forem encontrados. Esta é uma maneira prolixa de fazer isso, mas poderíamos alimentar os arquivos encontrados por find
into xargs
que então os canaliza tar
para criar um arquivo desses arquivos. Executaremos este comando em um diretório que contém muitos arquivos PAGE do sistema de ajuda.
find ./ -name "*.page" -type f -print0 | xargs -0 tar -cvzf page_files.tar.gz
O comando é composto de diferentes elementos.
- find ./ -name “*.page” -type f -print0: A ação find começará no diretório atual, procurando por nome por arquivos que correspondam à string de pesquisa “*.page”. Os diretórios não serão listados porque estamos dizendo especificamente para procurar apenas arquivos, com
-type f
. O argumentoprint0
dizfind
para não tratar o espaço em branco como o final de um nome de arquivo. Isso significa que os nomes de arquivos com espaços neles serão processados corretamente. - xargs -o : Os argumentos
-0xargs
para não tratar o espaço em branco como o final de um nome de arquivo. - tar -cvzf page_files.tar.gz : Este é o comando
xargs
que vai alimentar a lista de arquivos defind
. O utilitário tar criará um arquivo chamado “page_files.tar.gz”.
Podemos usar ls
para ver o arquivo que é criado para nós.
ls *.gz
O arquivo é criado para nós. Para que isso funcione, todos os nomes de arquivos precisam ser passados para tar
en masse , que foi o que aconteceu. Todos os nomes de arquivo foram marcados no final do tar
comando como uma linha de comando muito longa.
Você pode optar por executar o comando final em todos os nomes de arquivo de uma vez ou invocado uma vez por nome de arquivo. Podemos ver a diferença facilmente canalizando a saída xargs
para o utilitário de contagem de linhas e caracteres wc
.
Este comando canaliza todos os nomes de arquivos wc
de uma vez. Efetivamente, xargs
constrói uma longa linha de comando para wc
cada um dos nomes de arquivo nela contidos.
find . -name "*.page" -type f -print0 | xargs -0 wc
As linhas, palavras e caracteres de cada arquivo são impressos, juntamente com o total de todos os arquivos.
Se usarmos a opção xarg
‘s -I
(replace string) e definirmos um token de string de substituição—neste caso ” {}
“—o token é substituído no comando final por cada nome de arquivo por vez. Isso significa que wc
é chamado repetidamente, uma vez para cada arquivo.
find . -name "*.page" -type f -print0 | xargs -0 -I "{}" wc "{}"
A saída não está bem alinhada. Cada invocação de wc
opera em um único arquivo, portanto wc
, não tem nada para alinhar a saída. Cada linha de saída é uma linha de texto independente.
Como wc
só pode fornecer um total quando opera em vários arquivos ao mesmo tempo, não obtemos as estatísticas resumidas.
A opção find -exec
O comando find
tem um método interno de chamar programas externos para realizar processamento adicional nos nomes de arquivo que ele retorna. A opção exec
(executar) tem uma sintaxe semelhante, mas diferente do comando xargs
.
find . -name "*.page" -type f -exec wc -c "{}" \;
Isso contará as palavras nos arquivos correspondentes. O comando é composto por esses elementos.
- find . : inicia a pesquisa no diretório atual. O comando
find
é recursivo por padrão, portanto, os subdiretórios também serão pesquisados. - -name “*.page” : Estamos procurando arquivos com nomes que correspondam à string de pesquisa “*.page”.
- -type f : Estamos apenas procurando por arquivos, não por diretórios.
- -exec wc : Vamos executar o comando
wc
nos nomes dos arquivos que correspondem à string de pesquisa. - -w : Quaisquer opções que você deseja passar para o comando devem ser colocadas imediatamente após o comando.
- “{}” : o espaço reservado “{}” representa cada nome de arquivo e deve ser o último item na lista de parâmetros.
- \;: Um ponto e vírgula “;” é usado para indicar o fim da lista de parâmetros. Ele deve ser escapado com uma barra invertida “\” para que o shell não o interprete.
Quando executamos esse comando, vemos a saída wc
. A -c
(contagem de bytes) limita sua saída ao número de bytes em cada arquivo.
Como você pode ver, não há total. O comando wc
é executado uma vez por nome de arquivo. Ao substituir um sinal de mais “ +
” pelo ponto e vírgula final “ ;
” podemos mudar -exec
comportamento do ‘ para operar em todos os arquivos de uma vez.
find . -name "*.page" -type f -exec wc -c "{}" \+
Obtemos o resumo total e os resultados tabulados ordenadamente que nos dizem que todos os arquivos foram passados para wc
uma longa linha de comando.
exec Realmente significa exec
A opção -exec
(execute) não inicia o comando executando-o no shell atual. Ele usa o exec integrado do Linux para executar o comando, substituindo o processo atual – seu shell – pelo comando. Portanto, o comando que é iniciado não está sendo executado em um shell. Sem um shell, você não pode obter a expansão do shell de curingas e não tem acesso a aliases e funções do shell.
Este computador tem uma função shell definida chamada words-only
. Isso conta apenas as palavras em um arquivo.
function words-only () { wc -w $ 1 }
Talvez uma função estranha, “somente palavras” seja muito mais longa para digitar do que “wc -w”, mas pelo menos significa que você não precisa se lembrar das opções de linha de comando para wc
. Podemos testar o que ele faz assim:
words-only user_commands.page
Isso funciona muito bem com uma invocação de linha de comando normal. Se tentarmos invocar essa função usando find
a -exec
opção , ela falhará.
find . -name "*.page" -type f -exec words-only "{}" \;
O find
comando não pode encontrar a função shell e a -exec
ação falha.
Para superar isso, podemos com o find
lançar um shell Bash e passar o restante da linha de comando para ele como argumentos para o shell. Precisamos colocar a linha de comando entre aspas duplas. Isso significa que precisamos escapar das aspas duplas que estão ao redor da string de substituição “ {}”.
Antes de podermos executar o comando find
, precisamos exportar nossa função shell com a opção -f
(como função):
export -f words-only
find . -name "*.page" -type f -exec bash -c "words-only \"{}\"" \;
Isso é executado conforme o esperado.
Usando o nome do arquivo mais de uma vez
Se você quiser encadear vários comandos, você pode fazê-lo e pode usar a {}
string de substituição “ ” em cada comando.
find . -name "*.page" -type f -exec bash -c "basename "{}" && words-only "{}"" \;
Se subirmos cd um nível do diretório “pages” e executarmos esse comando, find
ainda descobriremos os arquivos PAGE porque ele pesquisa recursivamente. O nome do arquivo e o caminho são passados para nossa função words-only
como antes. Puramente por motivos de demonstração de uso -exec
com dois comandos, também estamos chamando o comando basename
para ver o nome do arquivo sem seu caminho.
Tanto o comando basename
quanto a função shell words-only
têm os nomes dos arquivos passados a eles usando uma string de substituição “ {} ”.
Cavalos para cursos
Há uma carga de CPU e uma penalidade de tempo para chamar repetidamente um comando quando você pode chamá-lo uma vez e passar todos os nomes de arquivo para ele de uma só vez. E se você estiver invocando um novo shell toda vez para iniciar o comando, essa sobrecarga fica pior.
Mas às vezes – dependendo do que você está tentando alcançar – você pode não ter outra opção. Qualquer que seja o método que sua situação exija, ninguém deve se surpreender que o Linux forneça opções suficientes para que você possa encontrar aquele que atenda às suas necessidades específicas.