Xargs разделяется на новые строки, а не пробелы
вот моя короткая проблема
$ echo 'for i in [email protected]; do echo arg: $i; done; echo DONE' > /tmp/test.sh
$ echo "ac\nbc\ncc\n" | xargs bash /tmp/test.sh
arg: ac
arg: bc
arg: cc
DONE
Это то, что я ожидаю, но
$ echo "ac s\nbc s\ncc s\n" | xargs -d \n bash /tmp/test.sh
arg: ac
arg: s
arg: bc
arg: s
arg: cc
arg: s
DONE
Должен ли выход быть?
arg: ac s
arg: bc s
arg: cc s
DONE
Как получить второй вывод с помощью xargs?
Ответы
Ответ 1
Try:
printf %b 'ac s\nbc s\ncc s\n' | xargs -d '\n' bash /tmp/test.sh
Вы пренебрегли цитатой \n
, переданной в -d
, что означает, что только n
, а не \n
был передан xargs
в качестве разделителя - оболочки "\
(когда оболочка анализирует некорректную строку, \
функционирует как escape-символ, если обычный символ следует за \
- n
в этом случае - используется только обычный символ).
Также посоветуйте @glenn jackman советовать удвоить котировку [email protected]
внутри script (или вообще опустить часть in "[email protected]"
).
Также: xargs -d
является расширением GNU, которое, например, не будет работать на FreeBSD/macOS. Чтобы он работал там, см. Решение @glenn jackman xargs -0
.
Обратите внимание, что я использую printf
, а не echo
, чтобы убедиться, что экземпляры \n
в строке интерпретируются как новые строки во всех оболочках, подобных Bourne:
В bash
и ksh
[1]2 → по умолчанию используется NOT интерпретация \
управляемых последовательностей (для этого вы должны использовать -e
) - в отличие от zsh
и строго POSIX-совместимые оболочки, такие как dash
.
Поэтому printf
является более переносимым выбором.
[1] Согласно руководству, ksh
echo
встроенный проявляет то же поведение, что и внешняя утилита echo
основной платформы хоста; в то время как это может различаться на разных платформах, реализации Linux и BSD/OSX не интерпретируют escape-последовательности \
по умолчанию.
Ответ 2
В вашей оболочке script необходимо использовать "[email protected]"
not [email protected]
См. http://www.gnu.org/software/bash/manual/bashref.html#Special-Parameters
Я вижу в руководстве xargs на моей машине:
xargs считывает элементы со стандартного ввода, помечены пробелами [...] или символами новой строки
(акцент мой)
Таким образом:
$ echo $'ac s\nbc s\ncc s\n' | xargs bash /tmp/test.sh
arg: ac
arg: s
arg: bc
arg: s
arg: cc
arg: s
DONE
$ printf "%s\0" "ac s" "bc s" "cc s" | xargs -0 bash /tmp/test.sh
arg: ac s
arg: bc s
arg: cc s
DONE
С первым вы получите эквивалент
bash /tmp/test.sh ac s bc s cc s
против использования нулевого разделителя
bash /tmp/test.sh "ac s" "bc s" "cc s"
Вам нужно четко указать, что разделитель с xargs, когда данные содержат пробелы.
$ printf "%s\n" "ac s" "bc s" "cc s" | xargs -d $'\n' bash /tmp/test.sh
arg: ac s
arg: bc s
arg: cc s
DONE
$ echo $'ac s\nbc s\ncc s\n' | xargs -d $'\n' bash /tmp/test.sh
arg: ac s
arg: bc s
arg: cc s
arg:
DONE
Обратите внимание на дополнительный аргумент arg в последнем случае, echo
уже добавляет новую строку, поэтому вам не нужен дополнительный, если вы не используете echo -n