Я знаю 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, поэтому любая помощь приветствуется!
command-line
grep
xargs
Альфа Омега
источник
источник
Ответы:
Это передает вывод (stdout) * из
find
to в (stdin of) *grep 'stdlib.h'
как текст (т.е. имена файлов обрабатываются как текст).grep
выполняет свои обычные функции и находит соответствующие строки в этом тексте (любые имена файлов, которые сами содержат шаблон). Содержимое файлов никогда не читается.Это создает команду,
grep 'stdlib.h'
для которой каждый результатfind
является аргументом, поэтому она будет искать совпадения внутри каждого найденного файлаfind
(xargs
может рассматриваться как превращение его стандартного аргумента в аргументы для данных команд) *Используйте
-type f
в вашей команде поиска, иначе вы получите ошибкиgrep
для соответствующих каталогов. Кроме того, если в именах файлов есть пробелы, ониxargs
будут плохо работать, поэтому используйте нулевой разделитель, добавив-print0
иxargs -0
для более надежных результатов:* добавил эти дополнительные пояснительные замечания, как предложено в комментарии @cat
источник
|
трубы стандартный вывод в Grep в стандартный ввод , который не является такой же , как аргументы Grep и дает заблуждение результаты.find -name '*.c' -exec grep stdlib.h {} +
. Я почти никогда не использую xargs. Также удивило, что никто не упомянул, что xargs выполняет те же функции, что и подстановкаgrep $(find)
команд, поэтому я написал свой собственный ответ. Объяснение xargs как подстановки команд с меньшими ограничениями и проблемами кажется естественным.find -delete
для этого особого случая? Или для команд, отличных отrm
, если у вас есть GNU find, затем-exec some_command {} +
группируются в пакеты, такие как xargs, вместо этого\;
поведение выполнения команды отдельно для каждой.find
запускает команду для каждого файла тогда и только тогда, когда он использует-exec command \;
Both,xargs
и-exec command \+
будет вызывать команду с максимальным количеством аргументов, разрешенных системой. Другими словами, они эквивалентныxargs берет свой стандартный ввод и превращает его в аргументы командной строки.
find . -name '*.c' | xargs grep 'stdlib.h'
очень похоже наИ даст те же результаты, пока список имен файлов не слишком длинный для одной командной строки. (Linux поддерживает мегабайты текста в одной командной строке, поэтому обычно вам не нужны xargs.)
Но оба они отстой, потому что они ломаются, если ваши имена файлов содержат пробелы . Вместо этого
find -print0 | xargs -0
работает, но так жеЭто никогда нигде не передает имена файлов:
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 имеет несколько замечательных вещей.
источник
-d
установить разделитель, так что вы можете использовать его-d'\n'
для обработки списка, разделенного новой строкой , что может быть полезно, если вы обрабатываете список имен файлов в файле и т. Д. (Если имена файлов не имеют в нихmyfunc(){ local IFS=$'\n'; fgrep
stdlib.h` $ (find); }
также работает с тем же эффектом. Или, как однострочник,(IFS=...; cmd...)
подоболочка также работает, чтобы содержать изменение IFS без необходимости сохранять / восстанавливать его.command $( find )
вещи. Проблемные имена файлов с пробелами и специальными символами могут сломать этот тип вещей. По крайней мере, двойная кавычка команда подстановки.IFS
так что это эквивалентно использованиюxargs '-d\n'
. Раскрытие глобуса и обработка метасимволов оболочки происходят до эффектов подстановки команд, поэтому я думаю, что это безопасно даже с именами файлов, которые содержат$()
или>
. Согласился, что использование разделения слов при подстановке команд не является хорошей практикой, за исключением одноразового интерактивного использования, когда вы что-то знаете о именах файлов. Ноcommand "$(find)"
полезно, только если вы ожидаете, что оноОбычно
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' -exec grep 'stdlib.h' {}\;
будет генерировать по одномуgrep
процессу для каждого файла - это обычно считается плохой практикой и может создать большую нагрузку на систему, если будет найдено много файлов.grep 'stdlib.h' $(find . -name '*.c')
команда, скорее всего, потерпит неудачу, поскольку результат$(...)
операции превысит максимальную длину командной строки оболочкиКак упоминалось в других ответах, причина использования
-print0
аргумента tofind
в этом сценарии и-0
аргумента xargs заключается в том, что имена файлов с определенными символами (например, кавычки, пробелы или даже символы новой строки) по-прежнему обрабатываются правильно.источник