Comandos de tubulação após um xargs canalizado

38

HP-UX ***** B.11.23 U ia64 **** licença de usuário ilimitado

find . -type d -name *log* | xargs ls -la

fornece os nomes dos diretórios (aqueles que contêm logno nome do diretório) seguidos por todos os arquivos dentro desse diretório.

Os diretórios  /var/opt/SID/application_a/log/,  /var/opt/SID/application_b/log/,  /var/opt/SID/application_c/log/e assim por diante contêm arquivos de log.

Eu quero que apenas os dois últimos arquivos de log sejam listados pelo lscomando, que eu costumo encontrar usando ls -latr | tail -2.

A saída tem que ser algo como isto ..

/var/opt/SID/application_a/log/
-rw-rw-rw-   1 user1    user1      59698 Jun 11  2013 log1
-rw-rw-rw-   1 user1    user1      59698 Jun 10  2013 log2
/var/opt/SID/application_b/log/
-rw-rw-rw-   1 user1    user1      59698 Jun 11  2013 log1
-rw-rw-rw-   1 user1    user1      59698 Jun 10  2013 log2
/var/opt/SID/application_c/log/
-rw-rw-rw-   1 user1    user1      59698 Jun 11  2013 log1
-rw-rw-rw-   1 user1    user1      59698 Jun 10  2013 log2

find . -type d -name *log* | xargs ls -la | tail -2não me dá o resultado acima. O que recebo é uma lista dos dois últimos arquivos de find . -type d -name *log* | xargs ls -lacomando.

Então, posso canalizar comandos após um canal xargs? De que outra forma eu consulta, para obter a lista resultante de arquivos no formato acima?

find . -type d -name *log* | xargs sh -c "ls -ltr | tail -10"

dá-me uma lista de dez nomes de diretório dentro do diretório atual, o que acontece /var/opt/SIDe também não é o que eu quero.

anotherperson1
fonte
2
Você deve citar o *log*caso contrário, o shell o expandirá.
Anthon
Esteja ciente de que sh -cespera o nome do comando (parâmetro 0) como seu segundo argumento, então você deve sempre fazê-lo find . -type d -name *log* | xargs sh -c "ls -ltr | tail -10" lstail(observe o lstailno final, que servirá como $0para o shell criado). Caso contrário, o primeiro dos seus resultados preencherá essa função e não será utilizado.
Jonas

Respostas:

58

Você está quase lá. Em seu último comando, você pode usar -Ipara fazer o lscorreto

-I replace-str

    Substitua ocorrências de replace-str nos argumentos iniciais pelos nomes lidos na entrada padrão. Além disso, espaços em branco não citados não finalizam itens de entrada; em vez disso, o separador é o caractere de nova linha. Implica -xe -L 1.

Então com

find . -type d -name "*log*" | xargs -I {} sh -c "echo {}; ls -la {} | tail -2"

você echoencontrará o diretório encontrado finde faça o ls | tailmesmo.

fredtantini
fonte
encontrar . -type d -name " log " | xargs -I {} sh -c "echo {}; ls -ltr {} | grep -E \" file_in | file_out \ "| tail -5" Eu usei este.
precisa
3
Eu faço comxargs -n 1 sh -c 'echo $0'
Ginhing
11
no MacOS a substituição não funcionou dentro do comando citado, por isso echo $0foi útil (e mais compreensível)
mpuncel
11
Para fazê-lo funcionar com nomes de arquivos com espaços, uso -print0, xargs -0e escapar {}em aspas duplas dentro do shcomando:find . -type d -name "*log*" -print0 | xargs -0 -I {} sh -c "echo \"{}\";ls -la \"{}\" | tail -2"
Benedikt Köppel
Eu uso "xargs -n 1 sh -c" echo \ $ 0 | $ func "` se eu precisar usar a variável $ func
god
5

O GNU Parallel facilita esse tipo de tarefa:

find . -type d -name "*log*" | parallel --tag "ls -la {} | tail -2"

Se você não deseja fazer uma instalação completa do GNU Parallel, você pode fazer uma instalação mínima: http://git.savannah.gnu.org/cgit/parallel.git/tree/README

Ole Tange
fonte
2

Além de fredtantini e como um esclarecimento geral (já que os documentos são um pouco confusos):

Ele xargs -I {}pegará os caracteres '{}' da entrada padrão e os substituirá pelo que vier do canal. Isso significa que você pode substituir {}por qualquer combinação de caracteres (talvez para melhor atender ao seu gosto de programação preferido). Por exemplo : xargs -I % sh -c "echo %". Se você sempre usar o, xargs -I {}poderá substituí-lo por xargs -iabreviação.

O sh -ccomando dirá ao seu bash / shell para ler o próximo comando de uma string e não da entrada padrão. Portanto, escrever sh -c "echo something"é equivalente a echo something.

O xargs -I {} sh -c "echo {}"lerá a entrada que você criou com a sh -cqual está echo {}. Como você pediu para substituir {}os argumentos que obteve do tubo, é isso que acontecerá.

Você pode testar isso facilmente, mesmo sem tubulação, basta digitar o comando acima em um terminal. Tudo o que você escrever a seguir será enviado para o terminal (Ctrl-D para sair).

No ls -la {}comando, a mesma coisa acontece novamente. O {}é substituído pelo conteúdo do comando pre-pipe.

Borisu
fonte