Se você quiser que aliases sejam expandidos após xargs
, você pode fazer:
alias xargs='xargs '
No entanto, observe que apenas a primeira palavra após xargs
está sujeita à expansão de alias e que pode ter efeitos inesperados se você tiver aliases para comandos padrão.
$ alias xargs='xargs ' a='echo test'
$ set -x
$ echo x | xargs a
+ echo x
+ xargs echo test
test x
$ echo x | xargs -r a
+ echo x
+ xargs -r a
xargs: a: No such file or directory
Você pode querer chamar seu alias de outra coisa e usar um comportamento padrão mais sensato para xargs
. Por exemplo, com o GNU xargs
:
alias axargs='xargs -r -d "\n" '
Agora, a substituição do processo se expande para um argumento: o nome de um arquivo que, para <(...)
, contém a saída do comando (como uma transmissão ao vivo).
Com a saída de find
, isso é útil apenas para comandos que aceitam como argumento um nome de arquivo esperado para conter uma lista de arquivos delimitada por nova linha.
feh
é um deles:
feh -f <(find . -mtime -1 -type f -name '*.jpg')
Isso só funciona se os nomes de arquivo não contiverem caracteres de nova linha.
A implementação GNU de xargs
tem uma opção -a
para obter a lista de argumentos de um arquivo e combinada com -0
e a opção -print0
(ou -exec printf '%sfind
' {} +
) para cmdB
permite passar uma lista de nomes de arquivos de forma confiável:
xargs -r0a <(find ... -print0) feh....
Isso não ajuda em seu problema de alias.
Agora, se você quiser passar a saída de um comando como argumento (s) para outro comando, é aí que você usaria a substituição comando ao invés de processar substituição. Cuidado com algumas advertências embora.
cmdA "$(cmdB)"
passa a saída de cmdA
, sem os caracteres de nova linha à direita como um argumento para * * /etc/passwd .jpg
. Por exemplo, se você tiver três arquivos regulares (aqui com nomes incomuns embora perfeitamente válidos): foo.txt
, <nl><nl>
e <nl>
(onde find . -type f
significa um caractere de nova linha), a saída de cmdB
( ./* * /etc/passwd .jpg<nl>./foo.txt<nl>./<nl><nl><nl>
) será cmdA
, então ./* * /etc/passwd .jpg<nl>./foo.txt<nl>./
receberá um argumento cmdA
.
Isso provavelmente não é o que você quer. Você deseja que ./* * /etc/passwd
receba cada nome de arquivo como argumentos separados: ./foo.txt
, ./<nl><nl>
e find
.
Então, basicamente, você precisaria dividir a saída de cmdB
nos nomes de arquivo individuais. Os shells POSIX têm um operador para isso, o operador split + glob que é invocado implicitamente quando você deixa uma substituição de comando (ou expansão de parâmetro ou expansão aritmética) sem aspas.
cmdA $(cmdB)
dividirá a saída de $IFS
(sem os caracteres de nova linha à direita) nos caracteres ./* * /etc/passwd .jpg
(por espaço padrão, guia e nova linha) e, então, cada palavra estará sujeita a globbing.
No nosso exemplo acima, não é isso que queremos. Isso dividiria ./*
em *
, /etc/passwd
, .jpg
e ./*
e os *
e find
seriam adicionados à lista de arquivos no diretório atual.
O que queremos é dividir em caracteres de nova linha e não fazer parte da globbing. Isso é feito com:
IFS='
' # newline only
set -f
cmdA $(cmdB)
Isso ainda não funciona para nomes de arquivos contendo caracteres de nova linha. A saída de -print0
geralmente não é pós-processável, a menos que você use zsh
ou você pode garantir que não haverá nomes de arquivo com caracteres de nova linha.
Agora, apenas "$(cmdB)"
permite dividir em cmdB
caracteres:
cmdA ${(0)"$(cmdB)"}
dividiria cmdA
nas sequências de caracteres NUL. Ou:
IFS=$'cmdA ${$(find...):?no file}
' # no need for set -f in zsh
cmdA $(cmdB)
Outro problema com as abordagens de substituição de comandos é que se zsh
falhar e / ou não produzir nada, zsh
ainda será executado (sem argumento). Isso pode ser evitado com esta sintaxe (ainda com zsh
):
myalias ./**/*.jpg(.m-1)
Mas se você estiver usando find
, geralmente não precisa ter todos os problemas, pois jpg
suporta internamente a maior parte da funcionalidade de %code% . Por exemplo, você usaria:
alias xargs='xargs '
Para exibir os arquivos %code% modificados pela última vez nas últimas 24 horas.