Por que xargs é necessário?


25

Suponha que eu queira remover todos os arquivos em um diretório, exceto um chamado "notes.txt". Eu faria isso com o pipeline ls | grep -v "notes.txt" | xargs rm. Por que preciso de xargs se a saída do segundo canal é a entrada que a rm deve usar?

Para fins de comparação, o pipeline echo "#include <knowledge.h>" | cat > foo.cinsere o texto ecoado no arquivo sem o uso de xargs. Qual é a diferença entre esses dois pipelines?


3
Você não deve ls | grep -v "notes.txt" | xargs rmremover tudo, exceto notes.txt, ou em geral, nunca analisa a lssaída . Seu comando seria interrompido se um único arquivo contivesse um espaço, por exemplo. A maneira mais segura seria rm !(notes.txt)em Bash (com shopt -s extglobset), ou rm ^notes.txtno Zsh (com EXTENDED_GLOB) etc.
slhck

Para espaços a evitar que você poderia fazer find . -maxdepth 1 -mindepth 1 -print0 | xargs -0em vez de ls | xargs:-)
flob

Respostas:


35

Você está confundindo dois tipos muito diferentes de entrada: STDIN e argumentos. Argumentos são uma lista de cadeias de caracteres fornecidas ao comando quando ele é iniciado, geralmente especificando-as após o nome do comando (por exemplo, echo these are some argumentsou rm file1 file2). STDIN, por outro lado, é um fluxo de bytes (às vezes texto, às vezes não) que o comando pode (opcionalmente) ler após o início. Aqui estão alguns exemplos (observe que catpode aceitar argumentos ou STDIN, mas faz coisas diferentes com eles):

echo file1 file2 | cat    # Prints "file1 file2", since that's the stream of
                          # bytes that echo passed to cat's STDIN
cat file1 file2    # Prints the CONTENTS of file1 and file2
echo file1 file2 | rm    # Prints an error message, since rm expects arguments
                         # and doesn't read from STDIN

xargs pode ser pensado como a conversão de entrada no estilo STDIN em argumentos:

echo file1 file2 | cat    # Prints "file1 file2"
echo file1 file2 | xargs cat    # Prints the CONTENTS of file1 and file2

echo na verdade, faz mais ou menos o contrário: ele converte seus argumentos em STDOUT (que pode ser canalizado para o STDIN de algum outro comando):

echo file1 file2 | echo    # Prints a blank line, since echo doesn't read from STDIN
echo file1 file2 | xargs echo    # Prints "file1 file2" -- the first echo turns
                                 # them from arguments into STDOUT, xargs turns
                                 # them back into arguments, and the second echo
                                 # turns them back into STDOUT
echo file1 file2 | xargs echo | xargs echo | xargs echo | xargs echo    # Similar,
                                 # except that it converts back and forth between
                                 # args and STDOUT several times before finally
                                 # printing "file1 file2" to STDOUT.

9

catrecebe entrada STDINe rmnão recebe . Para esses comandos, você precisa xargspercorrer STDINlinha por linha e executar os comandos com os parâmetros da linha de comando.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.