Вы могли всегда сохранять старую версию своей любимой ОС для этой задачи со старыми драйверами, работающими в VM (например, VirtualBox).
Часть проблемы - то, что строка, возвращенная args.sh, не анализируется то же как прямая команда, но только значением $IFS ($' \t\n'
). Попытайтесь включить трассировку команды с set -x
:
$ sh /tmp/test.sh $(sh /tmp/args.sh)
++ sh /tmp/args.sh
+ sh /tmp/test.sh 1 '"Two' 'words"' 3
Argument 1: 1
Argument 2: "Two
Argument 3: words"
$
Заметьте строку, запускающуюся с сингла +
: существует четыре аргумента, '"Two'
и 'words"'
два проанализированных как отдельные аргументы. То, что Вы хотели бы сделать, изменить $IFS.
$ set -x
$ IFS='"'
+ IFS='"'
$ sh /tmp/test.sh $(sh /tmp/args.sh)
++ sh /tmp/args.sh
+ sh /tmp/test.sh '1 ' 'Two words' ' 3'
Argument 1: 1
Argument 2: Two words
Argument 3: 3
$
Это не будет работать на каждый вывод. Лучшая вещь сделать состоит в том, чтобы изменить вывод args.sh для разделения вывода чем-то другим от пространства, например, запятая или двоеточие:
$ cat /tmp/args.sh
#!/bin/sh
#This script is named: args.sh
echo "1,Two words,3"
$ IFS=,
$ sh /tmp/test.sh $(sh /tmp/args.sh)
+ sh /tmp/args.sh
+ sh /tmp/test.sh 1 Two words 3
Argument 1: 1
Argument 2: Two words
Argument 3: 3
$
Когда Вы оставляете подстановку переменных $var
или замена команды $(cmd)
неупомянутый, результат подвергается следующим преобразованиям:
IFS
(см. 1, 2).Обратите внимание, что результатом не является строка, а список строк. Кроме того, отметьте это символы кавычки как "
не включены здесь; они - часть исходного синтаксиса оболочки, не строкового расширения.
Общее правило программирования оболочки состоит в том, чтобы всегда помещать двойные кавычки вокруг переменной и замен команды, если Вы не знаете, почему необходимо оставить их. Таким образом в test.sh
, записать echo "Argument 1: $1"
. Передать аргументы test.sh
, Вы в беде: необходимо передать список слов от args.sh
кому: test.sh
, но Ваш выбранный метод включает замену команды и который только обеспечивает путь к простой строке.
Если можно гарантировать, что аргументы, которые будут переданы, не содержат новых строк, и приемлемо изменить процесс вызова немного, можно установить IFS
содержать только новую строку. Удостоверьтесь это args.sh
выводы точно одно имя файла на строку без случайных кавычек.
IFS='
'
test.sh $(args.sh)
unset IFS
Если аргументы могут содержать произвольные символы (по-видимому, кроме пустых байтов, которые Вы не можете передать как аргументы), необходимо будет выполнить некоторое кодирование. Любое кодирование сделает; конечно, это не совпадет с передачей аргументов непосредственно: это не возможно. Например, в args.sh
(замена \t
фактическим символом табуляции, если Ваша оболочка не поддерживает его):
for x; do
printf '%s_\n' "$x" |
sed -e 's/q/qq/g' -e 's/ /qs/g' -e 's/\t/qt/g' -e 's/$/qn/'
done
и в test.sh
:
for arg; do
decoded=$(printf '%s\n' "$arg" |
sed -e 's/qs/ /g' -e 's/qt/\t/g' -e 's/qn/\n/g' -e 's/qq/q/g')
decoded=${decoded%_qn}
# process "$decoded"
done
Можно предпочесть изменяться test.sh
принять список строк, как введено. Если строки не содержат новые строки, вызвать args.sh | test.sh
и используйте это в args.sh
(объяснение):
while IFS= read -r line; do
# process "$line"
done
Другой метод, который предотвращает потребность в заключении в кавычки в целом, должен вызвать второй сценарий сначала.
…
args.sh "$@"