Разница между «xargs» и подстановкой команд?

14

Во многих случаях я использую подстановку команд вместо xargs. Например, так rm $(ls)же, какls | xargs rm

Какие на самом деле различия между ними?

Я думаю, что одно из отличий заключается в том, что подстановка команд выполняется в подоболочке, а xargsв текущей оболочке, но я не уверен.

Пожалуйста, перечислите различия.

Sinoosh
источник

Ответы:

9

Одно из отличий заключается в том, что при использовании подстановки команд вместо канала размер передаваемых данных ограничивается размером буфера команд, поэтому в некоторых случаях он усекается без предупреждения. Это также означает, что весь вывод команды должен быть произведен и сохранен в памяти, прежде чем он будет передан следующей команде, поэтому для больших выходных данных вы можете использовать гораздо больше памяти, чем необходимо.

Еще одна проблема, связанная с первым методом, заключается в том, что выходные данные разделяются на пробелы, поэтому вы не можете обрабатывать имена файлов с пробелами в них. xargsНа проблему также влияют пробельные символы, но ее можно исправить, изменив используемый разделитель. Кстати, чтобы правильно обрабатывать имена файлов, вам нужно будет использовать нулевой байт в качестве разделителя во втором примере.

Третья проблема заключается в том, что глобусы расширяются, поэтому, если в имени файла есть звездочки или вопросительные знаки, будут неожиданные результаты.

Вы можете найти хорошую дискуссию по этому вопросу здесь: http://mywiki.wooledge.org/ParsingLs

Правильный синтаксис будет

echo rm *

или если вы должны использовать Xargs,

find . -maxdepth 1 -print0 | xargs -0 echo rm

Удалить, echoкогда вывод выглядит правильно.

user000001
источник
1
@Sinoosh: xargsтакже запускается в подоболочке из-за канала, если вы не включите его shopt -s lastpipe, и в этом случае он будет работать в текущей оболочке. Я не думаю, что запуск в подоболочке является проблемой, хотя в этом случае, поскольку вы не меняете никаких переменных.
user000001
1
@Sinoosh: чтобы передавать аргументы один за другим, вы можете использовать -lфлаг, например find . -maxdepth 1 -print0 | xargs -0 -l rm. Что касается второго вопроса, вы не можете использовать lsс, xargs -0потому что ls не разделяет вывод на нулевой бут, но с символами новой строки (которые действительны в именах файлов BTW)
user000001
1
@Sinoosh: Не первый абзац, а второй: xargs без -0опции страдает проблемой пробелов.
user000001
1
Читать man xargs, использовать echoдля тестирования, нет rm. xargsпозволяет нам превышать пределы оболочки (некоторый буфер ограничен 65K, список имен файлов - нет).
Вальтинатор
1
@Sinoosh: у меня нет удобного справочника, но вы можете напечатать, xargs --show-limitsи вы увидите ограничение, установленное в вашей системе,
user000001