Передача нескольких параметров через xargs


17

Я хотел бы иметь возможность использовать xargsдля выполнения нескольких параметров в разных частях команды.

Например, следующее:

echo {1..8} | xargs -n2 | xargs -I v1 -I v2 echo the number v1 comes before v2

Я надеюсь, что это вернется

the number 1 comes before 2
the number 3 comes before 4 

... так далее

Это достижимо? Я подозреваю, что мое многократное использование -Iневерно.

Ответы:


29

Я считаю, что вы не можете использовать -Iэтот способ. Но вы можете получить желаемый эффект / поведение, сказав:

echo {1..8} | xargs -n2 sh -c 'echo "the number $1 comes before $2"' sh

По сути, это создает специальный однострочный сценарий оболочки, который xargsвыполняется через sh -c. Два значения, которые xargsанализируются из входных данных, передаются в этот «сценарий». Затем оболочка назначает эти значения $1и $2, на которые вы затем можете ссылаться в «сценарии».


4
Спасибо - это здорово. Хотя я читал этого человека для sh и изо всех сил стараюсь понять, что делает второй вызов sh, и, следовательно, почему его пропуск дает «половину» результата.
Дэмиен Сойер

6
@DamienSawyer Второго звонка нет sh. Трейлинг shв конце - это то, что ставится $0. $0обычно это имя переводчика или сценария.
Кусалананда

Я просто заменил трейлинг, shс echo $shкоторым он работает. Итак, финал shфункционирует как заполнитель
кенн

Ну, это упрощение того, что сказал Кусалананда.
Скотт

6

В конкретном случае printfвы всегда можете сделать:

echo {1..8} | xargs printf 'the number %s comes before %s\n'

потому что printfимеет внутренне- xargsподобную способность выполнять несколько раз, если ему дается больше аргументов, чем нужно для одного вызова. Хотя это имеет небольшое преимущество перед

printf 'the number %s comes before %s\n' {1..8}

А для больших списков простая xargsкоманда может привести к xargsзапуску нескольких экземпляров printf, некоторые из которых могут иметь нечетное количество аргументов. Вы можете перейти -n 1000к этому, xargsчтобы защититься от этого, где 1000 - это четное число, которое должно быть достаточно маленьким, чтобы не достигать слишком длинного предела списка arg и достаточно большим, чтобы избежать запуска такого количества printfs.

Обратите внимание, что xargsбудет вызывать не встроенную оболочку printf, а внешнюю printf, с каждым вызовом в отдельном новом процессе.

Также обратите внимание, что для пустого ввода, за исключением некоторых BSD, оно все равно будет запускаться printfодин раз без аргументов. GNU xargsи совместимые имеют -r (или --no-run-if-empty) возможность избежать этого.

Для ясности, этот простой ответ специфичен для вашего printfпримера и не будет работать в общем случае, когда вы должны передавать команде два параметра за раз (как diff, например, будет). Чтобы решить общую проблему с zsh, вы можете использовать:

for i j ({1..8}) echo "the number $i comes before $j"

(1) ИМХО, zshчасть вышеизложенного является реальным ответом, а часть xargs-with-no-options - просто странностью. В таком случае я бы посоветовал поставить реальный ответ первым. (2) Я полагаю, у вас есть причина не использовать кавычки в вашей zshкоманде. Если это так, вы можете заявить об этом, чтобы люди не прочитали вышеизложенное и не подумали, что цитаты не важны. (Или просто включите их, так как они не болят.)
Скотт

Это действительно круто. Я приземлился здесь в поисках чего-то подобного, где я не знал заранее, сколько аргов я собирался получить, которые должны были быть помещены в командную строку следующего аргумента. сделал что-то вродеawk -F'\t' '/match/{printf $1"\0"$2"\0"}' | xargs -0 printf -- '-args1 "%s" -args2 "%s"' | xargs mycommand
Keithpjolley

@keithpjolley, вы используете его -0на первом, xargsчтобы сделать его более надежным, побеждено тем, что вы не используете его на втором. Кроме того, первым аргументом printf(как для автономной утилиты, так и awkдля printf()функции) является формат, вам не следует использовать там переменные. Здесь вы могли бы сделать awk -F'\t' '/match/{printf "-args1\0%s\0-args2\0%s\0", $1, $2}' | xargs -n400 -r0 mycommand. Опять же, -n400необходимо обеспечить xargsпередачу числа аргументов, кратного 4. (обратите внимание, что не все awkреализации поддерживают использование \0здесь).
Стефан Шазелас

-0Я не использовал его, чтобы сделать его более надежным, использовал его, чтобы он делал то, что хотел, что он и делает.
Keithpjolley

2

попробуй это:

echo {1..8} |xargs -n 2 bash -c 'echo "the number $0 comes before $1"'

2
Это будет работать в этом случае, но лучше запустить sh -cскрипт с sh(или с чем угодно) в $0. Обратите внимание, что $0это не включено, $@если это должно было использоваться sh -cсценарием, например, если сценарий былecho "the two numbers were $@"
Kusalananda
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.