Зачем нужен xargs?

5629
seewalker

Предположим, я хочу удалить все файлы в каталоге, кроме одного с именем "notes.txt". Я бы сделал это с конвейером ls | grep -v "notes.txt" | xargs rm. Зачем мне нужен xargs, если на выходе второго канала указан вход, который должен использовать rm?

Для сравнения, конвейер echo "#include <knowledge.h>" | cat > foo.cвставляет отраженный текст в файл без использования xargs. В чем разница между этими двумя трубопроводами?

19
Вы не должны использовать `ls | grep -v "notes.txt" | xargs rm`, чтобы удалить все, кроме `notes.txt` или вообще [никогда не анализировать вывод` ls`] (http://mywiki.wooledge.org/ParsingLs). Ваша команда прервется, если, например, в одном файле будет пробел. Более безопасным способом будет `rm! (Notes.txt)` в Bash (с установленным `shopt -s extglob`) или` rm ^ notes.txt` в Zsh (с `EXTENDED_GLOB`) и т. Д. slhck 10 лет назад 3
Чтобы избежать пробелов, вы можете сделать `find. -maxdepth 1 -mindepth 1 -print0 | xargs -0` вместо `ls | xargs` :-) flob 9 лет назад 0

2 ответа на вопрос

29
Gordon Davisson

You are confusing two very different kinds of input: STDIN and arguments. Arguments are a list of strings provided to the command as it starts, usually by specifying them after the command name (e.g. echo these are some arguments or rm file1 file2). STDIN, on the other hand, is a stream of bytes (sometimes text, sometimes not) that the command can (optionally) read after it starts. Here are some examples (note that cat can take either arguments or STDIN, but it does different things with them):

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 can be thought of as converting STDIN-style input to arguments:

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

echo actually does more-or-less the opposite: it converts its arguments to STDOUT (which can be piped to some other command's STDIN):

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. 
8
Alex P.

cat takes input from STDIN and rm does not. For such commands you need xargs to iterate through STDIN line by line and execute the commands with command line parameters.