cmd2 'cmd1' vs cmd1 | xargs cmd2

4

Estou tentando encontrar um arquivo com find e depois passar o caminho encontrado para sqlite3 . Eu estou apenas solto no prompt sqlite> se meu comando estiver no formato:

sqlite3 'find . -type f -iname "*.db" | head -n1'

Mas esses formulários não funcionam:

find . -type f -iname "*.db" | head -n1 | xargs sqlite3
find . -type f -iname "*.db" | head -n1 | xargs -I% sh -c 'sqlite3 %;'

Por que os últimos comandos simplesmente não fazem nada?

    
por wes 11.12.2014 / 22:45

1 resposta

6

Em:

... | xargs cmd

dependendo da implementação, o stdin de cmd é /dev/null ou esse canal. Não pode ser o stdin externo, uma vez que é perdido por causa da tubulação.

$ echo /proc/self/fd/0 | gnu-xargs ls -ld
lr-x------ 1 me me 64 Dec 11 22:04 /proc/self/fd/0 -> /dev/null
$ echo /proc/self/fd/0 | busybox-or-solaris-...-xargs ls -ld
lr-x------    1 me me        64 Dec 11 22:04 /proc/self/fd/0 -> pipe:[99839]

Em ambos os casos, sqlite3 não poderá ler nenhuma entrada sua.

O:

sqlite3 'find . -type f -iname "*.db" | head -n1'
O comando

pega a primeira linha do primeiro caminho de arquivo retornado por find , divide-o de acordo com $IFS , executa globbing neles e passa as palavras resultantes como argumentos diferentes para sqlite3. Isso faz pouco sentido.

Com o GNU find (provavelmente o que você está usando desde que você esteja usando -iname ):

sqlite3 "$(find . -type f -iname "*.db" -print -quit)"

Usamos -exit para informar find para sair depois de imprimir o primeiro arquivo encontrado. Usamos a forma moderna de substituição de comandos $(...) e pulamos a parte split + glob (que não faz sentido) citando a substituição de comando.

Você também pode usar (ainda específico do GNU):

find . -type f -iname '*.db' \( -exec sqlite3 {} \; -o -true \) -quit

(embora você perca o status de saída de sqlite3 ).

com zsh :

setopt extendedglob # best in ~/.zshrc
sqlite3 ./**/*.(#i)db(D.[1])
    
por 11.12.2014 / 23:11