Как я могу передать все аргументы с помощью xargs в середине команды в Linux

Я хочу передать все файлы в качестве одного аргумента в Linux, но я не могу этого сделать.

Это работает

ls | sort -n | xargs  -i pdftk  {} cat output combinewd2.pdf

Это передает один аргумент на команду, но я хочу, чтобы все было в одной команде.


person user2027303    schedule 01.02.2013    source источник


Ответы (8)


Это один из способов сделать это

pdftk $(ls | sort -n) cat output combinewd2.pdf

или с помощью обратной кавычки

pdftk `ls | sort -n` cat output combinewd2.pdf

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

eval pdftk $(while IFS= read -r file; do
    echo \"$file\"
done < <(ls | sort -n)) cat output combinewd2.pdf

Предположим, что есть два файла с именами "0 foo" и "1 bar", тогда результатом eval будет нужная команда с именами файлов в двойных кавычках:

pdftk " 0 foo " " 1 bar " cat output combinewd2.pdf

Если имена файлов могут содержать символы новой строки, используйте команду find, см. обсуждение @joeytwiddle в комментариях к ответу @andrewdotn. Следующее решение также обрабатывает имена файлов с двойными кавычками, используя команду sed для выхода из двойных кавычек:

eval pdftk $(while IFS= read -r -d '' file; do
    echo \"$file\"
done < <(find . -maxdepth 1 -type f -print0 | \
    sed 's/"/\\"/g'| sort -zn)) cat output combinewd2.pdf
person amdn    schedule 01.02.2013
comment
Очень bash-ориентированный ответ, но тем не менее классный. Однако это не будет работать в csh/tcsh. (все комментарии по выбору оболочки › /dev/null) - person radical7; 01.02.2013
comment
Важно отметить, что это не будет работать с именами файлов, содержащими пробелы. Слова будут разбиты на отдельные аргументы. - person joeytwiddle; 24.02.2016
comment
@joeytwiddle, вы правы, я предлагаю решение с использованием eval - person amdn; 24.02.2016
comment
@joeytwiddle снова прав, добавлена ​​команда sed, чтобы избежать двойных кавычек - person amdn; 24.02.2016
comment
Я боюсь, что ваше решение eval не будет работать с именами файлов, содержащими " кавычки ". Мне нравится простота вашего $(...) подхода для тех случаев, когда мы знаем, что имена файлов не содержат пробелов. Я разместил свое решение как отдельный ответ. - person joeytwiddle; 24.02.2016
comment
Я не знаю, как сломать ваше sed решение. Отличная работа! :) - person joeytwiddle; 24.02.2016
comment
Спасибо! Ваш короче, вам тоже респект - person amdn; 24.02.2016
comment
Можете ли вы решить проблему с пробелами в именах файлов, изменив IFS, например. IFS=$'\n'; echo pre $(ls | sort -n) post ? - person DNA; 14.08.2017
comment
Используйте pdftk "$(ls | sort -n)" cat output combinewd2.pdf, чтобы не было проблем с пробелами или другими специальными символами. - person Mikko Rantalainen; 28.05.2020

Используйте вариант -I:

echo prefix | xargs -I % echo % post

Выход:

prefix post
person Hongbo Liu    schedule 01.11.2016
comment
Однако это не работает так, как хотелось бы (он вызывает команду три раза, а не один раз с тремя аргументами), если вы используете ls, а не echo в качестве ввода, что и пытается сделать OP... - person DNA; 14.08.2017
comment
Это обрабатывает строку repl как один аргумент., - person brian d foy; 14.02.2020

Это уродливо, но вы можете запустить sh -c и получить доступ к списку аргументов, переданных xargs как "${@}", вот так:

ls | sort -n | xargs -d'\n' sh -c 'pdftk "${@}" cat output combinewd2.pdf' "${0}"

Дополнительный "${0}" в конце присутствует потому, что, как сказано в sh справочной странице

-c строка

Если указан параметр -c, команды считываются из строки. Если после строки есть аргументы, они назначаются позиционным параметрам, начиная с $0.

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

$ seq 1 100 | xargs -I{} touch '{} with "spaces"'
$ ls
1 with "spaces"    31 with "spaces"  54 with "spaces"  77 with "spaces"
10 with "spaces"   32 with "spaces"  55 with "spaces"  78 with "spaces"
100 with "spaces"  33 with "spaces"  56 with "spaces"  79 with "spaces"
11 with "spaces"   34 with "spaces"  57 with "spaces"  8 with "spaces"
12 with "spaces"   35 with "spaces"  58 with "spaces"  80 with "spaces"
13 with "spaces"   36 with "spaces"  59 with "spaces"  81 with "spaces"
14 with "spaces"   37 with "spaces"  6 with "spaces"   82 with "spaces"
15 with "spaces"   38 with "spaces"  60 with "spaces"  83 with "spaces"
16 with "spaces"   39 with "spaces"  61 with "spaces"  84 with "spaces"
17 with "spaces"   4 with "spaces"   62 with "spaces"  85 with "spaces"
18 with "spaces"   40 with "spaces"  63 with "spaces"  86 with "spaces"
19 with "spaces"   41 with "spaces"  64 with "spaces"  87 with "spaces"
2 with "spaces"    42 with "spaces"  65 with "spaces"  88 with "spaces"
20 with "spaces"   43 with "spaces"  66 with "spaces"  89 with "spaces"
21 with "spaces"   44 with "spaces"  67 with "spaces"  9 with "spaces"
22 with "spaces"   45 with "spaces"  68 with "spaces"  90 with "spaces"
23 with "spaces"   46 with "spaces"  69 with "spaces"  91 with "spaces"
24 with "spaces"   47 with "spaces"  7 with "spaces"   92 with "spaces"
25 with "spaces"   48 with "spaces"  70 with "spaces"  93 with "spaces"
26 with "spaces"   49 with "spaces"  71 with "spaces"  94 with "spaces"
27 with "spaces"   5 with "spaces"   72 with "spaces"  95 with "spaces"
28 with "spaces"   50 with "spaces"  73 with "spaces"  96 with "spaces"
29 with "spaces"   51 with "spaces"  74 with "spaces"  97 with "spaces"
3 with "spaces"    52 with "spaces"  75 with "spaces"  98 with "spaces"
30 with "spaces"   53 with "spaces"  76 with "spaces"  99 with "spaces"
$  ls | sort -n | xargs -d'\n' sh -c 'set -x; pdftk "${@}" cat output combinewd2.pdf' "${0}"
+ pdftk '1 with "spaces"' '2 with "spaces"' '3 with "spaces"' '4 with "spaces"' '5 with "spaces"' '6 with "spaces"' '7 with "spaces"' '8 with "spaces"' '9 with "spaces"' '10 with "spaces"' '11 with "spaces"' '12 with "spaces"' '13 with "spaces"' '14 with "spaces"' '15 with "spaces"' '16 with "spaces"' '17 with "spaces"' '18 with "spaces"' '19 with "spaces"' '20 with "spaces"' '21 with "spaces"' '22 with "spaces"' '23 with "spaces"' '24 with "spaces"' '25 with "spaces"' '26 with "spaces"' '27 with "spaces"' '28 with "spaces"' '29 with "spaces"' '30 with "spaces"' '31 with "spaces"' '32 with "spaces"' '33 with "spaces"' '34 with "spaces"' '35 with "spaces"' '36 with "spaces"' '37 with "spaces"' '38 with "spaces"' '39 with "spaces"' '40 with "spaces"' '41 with "spaces"' '42 with "spaces"' '43 with "spaces"' '44 with "spaces"' '45 with "spaces"' '46 with "spaces"' '47 with "spaces"' '48 with "spaces"' '49 with "spaces"' '50 with "spaces"' '51 with "spaces"' '52 with "spaces"' '53 with "spaces"' '54 with "spaces"' '55 with "spaces"' '56 with "spaces"' '57 with "spaces"' '58 with "spaces"' '59 with "spaces"' '60 with "spaces"' '61 with "spaces"' '62 with "spaces"' '63 with "spaces"' '64 with "spaces"' '65 with "spaces"' '66 with "spaces"' '67 with "spaces"' '68 with "spaces"' '69 with "spaces"' '70 with "spaces"' '71 with "spaces"' '72 with "spaces"' '73 with "spaces"' '74 with "spaces"' '75 with "spaces"' '76 with "spaces"' '77 with "spaces"' '78 with "spaces"' '79 with "spaces"' '80 with "spaces"' '81 with "spaces"' '82 with "spaces"' '83 with "spaces"' '84 with "spaces"' '85 with "spaces"' '86 with "spaces"' '87 with "spaces"' '88 with "spaces"' '89 with "spaces"' '90 with "spaces"' '91 with "spaces"' '92 with "spaces"' '93 with "spaces"' '94 with "spaces"' '95 with "spaces"' '96 with "spaces"' '97 with "spaces"' '98 with "spaces"' '99 with "spaces"' '100 with "spaces"' cat output combinewd2.pdf

Все аргументы приведены правильно. Обратите внимание, что это не удастся, если какие-либо имена файлов содержат новые строки, и что ls -v в основном ls | sort -n.

person andrewdotn    schedule 01.02.2013
comment
Это работает с именами файлов, содержащими пробелы, но не с именами файлов, содержащими символы новой строки. Хотя они не очень распространены, их можно правильно обработать с помощью: find . -type f -maxdepth 1 -print0 | sort -zn | xargs -0 sh -c ... - person joeytwiddle; 24.02.2016
comment
Хотя если мы используем find, то xargs нам вообще не нужно! Мы можем использовать find ... -exec [command] {} +, как рекомендовано в BashFAQ/020. - person joeytwiddle; 24.02.2016
comment
@joeytwiddle Да, используйте find вместо ls, если в именах файлов могут быть новые строки. - person andrewdotn; 24.02.2016
comment
Но в этом случае мы не можем использовать find напрямую из-за желания OP сортировать. Кстати, я думаю, что "$0" должен идти внутри команды оболочки. Странная особенность sh -c 'foo' bar baz bim заключается в том, что bar передается как аргумент $0, а baz и bim — в $@, а foo< /i> быть казненным. Поэкспериментируйте с: sh -c 'echo "$0" "$@"' a b c - person joeytwiddle; 24.02.2016
comment
@joeytwiddle $0 находится снаружи, так что $0 родителя передается дочернему, но $@ расширяется до $1 ... из xargs. Это очень тонко, поэтому я начинаю с «Это некрасиво, но…» - person andrewdotn; 25.02.2016
comment
Ты совершенно прав. Когда есть 0 строк ввода, ваш "$0" внешний работает нормально, но мой "$0" внутри видит первый аргумент как "sh" или "bash"! Вот пример, который ломается (удалите grep для непустого ввода): seq 1 3 | grep X | xargs -d'\n' bash -c 'echo "$0" "${@}"' - person joeytwiddle; 12.03.2016
comment
хорошее решение! я продолжаю возвращаться к этому. Однако использование ${0} немного сбивает с толку. он также может быть sh или false или ignored, поскольку он просто используется для смещения позиционных параметров, полученных от xargs. - person RubyTuesdayDONO; 16.04.2020
comment
Хотя вы, вероятно, можете обойтись без передачи фиктивного значения, я передаю ${0} явно, чтобы значение ${0} в дочернем процессе было таким же, как и в родительском. - person andrewdotn; 17.04.2020

Это должно работать с именами файлов, содержащими пробелы, новые строки, апострофы и кавычки (все это возможно в файловых системах UNIX):

find . -maxdepth 1 -type f -print0 |
  sort -zn |
  xargs -0 sh -c 'pdftk "$@" cat output combinewd2.pdf' "$0"

Это может быть излишним по сравнению с принятым ответом, если вы знаете, что работаете с простыми именами файлов.

Но если вы пишете сценарий, который будет использоваться снова в будущем, желательно, чтобы он не взорвался однажды, когда встретит необычные (но действительные) входные данные.

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

Соответствующие опции -print0, -z и -0 сообщают каждой из программ, что ввод/вывод должен быть разделен нулевым байтом. Три разные программы, три разных аргумента!

person joeytwiddle    schedule 24.02.2016

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

  • сначала создайте команды с -I{} и "echo",
  • затем выполните команды с помощью «bash» (как если бы вы выполняли сценарий оболочки)

Вот пример переименования расширений с «.txt» на «.txt.json»:

find .|grep txt$|xargs -I{} echo "mv {} {}.json"|bash

Немного расширенный пример переименования .txt в .json (удаление расширения .txt)

find $PWD|grep txt$|cut -d"." -f1|xargs -I{} echo "mv {}.txt {}.json"|bash

Однажды у меня было требование добавить строку «Конец файла» ко всем файлам.

find .|grep txt|xargs -I{} echo "echo End of File >> {}"|bash

Если вы все сделаете правильно, xargs станет королем всех команд!

person Thyag    schedule 02.11.2018

Вы можете сделать это, объединив два вызова xargs. Используйте первый, чтобы объединить все аргументы в одну строку и передать ее в качестве параметра в echo, а второй, используя -I, чтобы поместить эту цепочку аргументов в нужное место, следующим образом:

ls | sort -n | xargs echo | xargs -I {} pdftk {} cat output combinewd2.pdf
person JakeRobb    schedule 20.03.2018
comment
Это обрабатывает replstr как один аргумент, поэтому pdftk ищет файл, в котором имена всех файлов объединены пробелами. - person brian d foy; 14.02.2020
comment
Интересно. Прошло почти два года; Я не пользователь pdftk, поэтому проверил это с помощью какой-то другой команды (которую я сейчас не помню). Это сработало для меня. Возможно, это может быть причуда pdftk или какой-то другой фактор. - person JakeRobb; 02.03.2020

Вот что я сделал для той же проблемы и фактически использую в производстве:

cat chapter_order-pdf-sample.txt | xargs -J % pdftk % cat output sample.pdf
person brian d foy    schedule 14.02.2020
comment
NB: -J отсутствует в GNU-версии xargs, поэтому вместо этого нужно использовать -I. - person stason; 22.10.2020

Я знаю, что это не вопрос ОП, но я нашел это полезным.

Если вы хотите перетасовать свои аргументы, вы можете использовать parallel в сочетании с xargs.

# limit the number of arguments per line
echo last first middle last first middle | xargs -n 3
last first middle
last first middle

GNU-parallel теперь может перетасовывать эти аргументы по желанию с аргументом --colsep.

echo last first middle last first middle | xargs -n 3 | parallel --colsep=" " echo {2} {3} {1}
first middle last
first middle last

Вы также можете добавить туда постоянные аргументы.

echo last first middle last first middle | xargs -n 3 | parallel --colsep=" " echo {2} {3} middle2 {1}
first middle middle2 last
first middle middle2 last
person ssanch    schedule 18.11.2020
comment
Почему бы просто не использовать parallel вместо комбинации xargs и parallel? - person goji; 04.02.2021
comment
Хороший вопрос. Это просто для создания своего рода разделенного пробелами STDIN списка аргументов. Эквивалентный способ сделать это: echo -e "last first middle\nlast first middle" | parallel ... - person ssanch; 22.03.2021