Что делает "xargs grep"?
Я знаю grep команда, и я узнаю о функциональности xargs, поэтому я прочитал эту страницу, которая дает несколько примеров о том, как использовать xargs команда.
Я запутался в последнем примере, пример 10. Он говорит: "Команда xargs выполняет команду grep, чтобы найти все файлы (среди файлов, предоставляемых командой find), которые содержали строку" stdlib.h ""
$ find . -name '*.c' | xargs grep 'stdlib.h'
./tgsthreads.c:#include
./valgrind.c:#include
./direntry.c:#include
./xvirus.c:#include
./temp.c:#include
...
...
...
Тем не менее, в чем разница с простым использованием
$ find . -name '*.c' | grep 'stdlib.h'
?
Очевидно, я все еще борюсь с тем, что именно делает xargs, поэтому любая помощь приветствуется!
4 ответа
$ find . -name '*.c' | grep 'stdlib.h'
Этот канал выводит (stdout)* из find к (стандарт) * grep 'stdlib.h' как текст (т.е. имена файлов рассматриваются как текст). grep выполняет свои обычные функции и находит соответствующие строки в этом тексте (любые имена файлов, которые сами содержат шаблон). Содержимое файлов никогда не читается.
$ find . -name '*.c' | xargs grep 'stdlib.h'
Это создает команду grep 'stdlib.h' к которому каждый результат из find является аргументом - поэтому он будет искать совпадения внутри каждого файла, найденного find (xargs можно рассматривать как превращение его стандартного ввода в аргументы данных команд) *
использование -type f в вашей команде поиска, или вы получите ошибки от grep для сопоставления каталогов. Кроме того, если имена файлов имеют пробелы, xargs будет плохо, так что используйте нулевой разделитель, добавив -print0 а также xargs -0 для более надежных результатов:
find . -type f -name '*.c' -print0 | xargs -0 grep 'stdlib.h'
* добавил эти дополнительные пояснительные замечания, как предложено в комментарии @cat
xargs берет свой стандартный ввод и превращает его в аргументы командной строки.
find . -name '*.c' | xargs grep 'stdlib.h' очень похоже на
grep 'stdlib.h' $(find . -name '*.c') # UNSAFE, DON'T USE
И даст те же результаты, пока список имен файлов не слишком длинный для одной командной строки. (Linux поддерживает мегабайты текста в одной командной строке, поэтому обычно вам не нужны xargs.)
Но оба они отстой, потому что они ломаются, если ваши имена файлов содержат пробелы. Вместо, find -print0 | xargs -0 работает, но так же
find . -name '*.c' -exec grep 'stdlib.h' {} +
Это никогда нигде не транслирует имена файлов: find упаковывает их в большую командную строку и запускает grep непосредственно.
\; вместо + запускает grep отдельно для каждого файла, что намного медленнее. Не делай этого. Но + это расширение GNU, так что вам нужно xargs сделать это эффективно, если вы не можете предположить, что GNU find.
Если вы пропустите xargs , find | grep сопоставляет свой шаблон со списком имен файлов, которые find печать.
Так что в этот момент вы могли бы просто сделать find -name stdlib.h, Конечно, с -name '*.c' -name stdlib.h вы не получите никакого вывода, потому что эти шаблоны не могут как совпадать, так и найти, что поведение по умолчанию - это И правила вместе.
Замена less в любой точке процесса, чтобы увидеть, какую продукцию производит любая часть конвейера.
Дальнейшее чтение: http://mywiki.wooledge.org/BashFAQ имеет несколько замечательных вещей.
В общем, xargs используется для случаев, когда вы бы трубу (с символом |) что-то от одной команды к другой (Command1 | Command2), но выходные данные из первой команды неправильно принимаются в качестве входных данных для второй команды.
Обычно это происходит, когда вторая команда не обрабатывает ввод данных через стандартный ввод (stdin) правильно (например: несколько строк в качестве ввода, способ установки строк, символы, используемые в качестве ввода, несколько параметров в качестве ввода, тип данных, полученный как вход и т. д.). Чтобы дать вам быстрый пример, протестируйте следующее:
Пример 1:
ls | echo - Это ничего не сделает, так как echo не знает, как обрабатывать ввод, который он получает. Теперь в этом случае, если мы используем xargs он будет обрабатывать ввод таким способом, который может быть правильно обработан echo (например: как одна строка информации)
ls | xargs echo - Это выведет всю информацию из ls в одну строку
Пример 2:
Допустим, у меня есть несколько файлов goLang в папке с именем go. Я бы посмотрел на них примерно так:
find go -name *.go -type f | echo - Но если символ трубы там и echo в конце концов, это не сработает.
find go -name *.go -type f | xargs echo - Здесь это будет работать благодаря xargs но если бы я хотел каждый ответ от find Команда в одну строку, я бы сделал следующее:
find go -name *.go -type f | xargs -0 echo - В этом случае, тот же выход из find будет показано echo,
Команды как cp, echo, rm, less и другие, которые нуждаются в лучшем способе обработки ввода, получают выгоду при использовании с xargs,
xargs используется для автоматической генерации аргументов командной строки на основе (обычно) списка файлов.
Таким образом, рассматривая некоторые альтернативы использованию следующих xargs команда:
find . -name '*.c' -print0 | xargs -0 grep 'stdlib.h'
Есть несколько причин использовать его вместо других опций, которые изначально не упоминались в других ответах:
find . -name '*.c' -exec grep 'stdlib.h' {}\;будет генерировать одинgrepпроцесс для каждого файла - это обычно считается плохой практикой и может создать большую нагрузку на систему, если найдено много файлов.- Если файлов много,
grep 'stdlib.h' $(find . -name '*.c')команда, скорее всего, потерпит неудачу, потому что вывод$(...)операция превысит максимальную длину командной строки оболочки
Как уже упоминалось в других ответах, причина использования -print0 аргумент find в этом сценарии и -0 Аргументом xargs является то, что имена файлов с определенными символами (например, кавычки, пробелы или даже символы новой строки) по-прежнему обрабатываются правильно.