У меня есть утилита (myutil
), которой нужно передать несколько параметров. Параметры могут (будут) содержать обратную косую черту и пробелы, поэтому их необходимо заключать в одинарные кавычки. Пример запуска этой утилиты:
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
Я работаю над скриптом, который будет считывать эти параметры из многострочного файла и передавать их в скрипт. Входной файл myinput.txt выглядит так:
# cat myinput.txt
ONE\APPLE
ONE\PEAR
TWO\RED GRAPE
TWO\TOMATO
Я использую следующий код для анализа файла и выполнения myutil
. Сценарий считывает каждую строку как аргумент и заключает ее в двойные кавычки (как myutil
будет ожидать значений с пробелами или специальными символами) и создает одну переменную для хранения всей строки аргумента:
#!/bin/sh
MYCOMMAND=myutil
if [ -f myinput.txt ]; then
ARGSLIST=`cat myinput.txt| sed -e 's/^/"/g' -e 's/$/"/g' | awk '{ printf "%s ", $0 }'`
$MYCOMMAND setOptions "${ARGSLIST}"
printf "%s\n" "$MYCOMMAND setOptions ${ARGSLIST}"
fi
Как и следовало ожидать, вывод этой команды на экран выглядит так, как и ожидалось:
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
Однако на самом деле это не то, что выполняется, основываясь на том, как myutil
обычно обрабатывает эту команду. Вместо этого myutil
обрабатывает это так, как если бы ВСЕ аргументы также были заключены в одинарные кавычки. Запуск этой отладки под sh
не отражает этого:
+ MYCOMMAND=myutil
+ [ -f myinput.txt ]
+ awk { printf "%s ", $0 }
+ sed -e s/^/"/g -e s/$/"/g
+ cat myinput.txt
+ ARGSLIST="ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
+ myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
+ printf %s\n myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
ОДНАКО запуск отладки под bash
, похоже, показывает, что на самом деле выполняется:
+ MYCOMMAND=myutil
+ '[' -f myinput.txt ']'
++ awk '{ printf "%s ", $0 }'
++ sed -e 's/^/"/g' -e 's/$/"/g'
++ cat myinput.txt
+ ARGSLIST='"ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO" '
+ myutil setOptions '"ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO" '
+ printf '%s\n' 'myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO" '
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
Вы можете увидеть строку отладки, которая выглядит так:
+ myutil setOptions '"ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO" '
Эта строка на самом деле выполняется на основе вывода, который я вижу в своей утилите, но на экран выводится вышеупомянутое за вычетом одинарных кавычек:
myutil setOptions "ONE\APPLE" "ONE\PEAR" "TWO\RED GRAPE" "TWO\TOMATO"
Мне нужно, чтобы то, что отображается на экране, было фактически выполнено, а не версия с одинарными кавычками, поскольку она предоставляет один гигантский параметр для myutil
, который бесполезен.
У меня есть два решения, ни одно из которых, я уверен, не является лучшим способом справиться с этой проблемой.
Во-первых, просто используйте eval:
#!/bin/sh
MYCOMMAND=myutil
if [ -f myinput.txt ]; then
ARGSLIST=`cat myinput.txt| sed -e 's/^/"/g' -e 's/$/"/g' | awk '{ printf "%s ", $0 }'`
eval $MYCOMMAND setOptions "${ARGSLIST}"
printf "%s\n" "$MYCOMMAND setOptions ${ARGSLIST}"
fi
Второй — использование xargs:
#!/bin/sh
MYCOMMAND=myutil
if [ -f myinput.txt ]; then
ARGSLIST=`cat myinput.txt| sed -e 's/^/"/g' -e 's/$/"/g' | awk '{ printf "%s ", $0 }'`
printf "%s\n" "$ARGSLIST" | xargs $MYCOMMAND setOptions
printf "%s\n" "$MYCOMMAND setOptions ${ARGSLIST}"
fi
Мне трудно поверить, что xargs
требуется, и я неоднократно читал, что использование eval
, вероятно, также не рекомендуется.
Я видел несколько похожих тем по этому поводу с советами по использованию массивов, но я не смог правильно применить их советы к моему примеру. Кроме того, мне нужно, чтобы это решение работало под bourne sh
и было максимально переносимым, поскольку оно будет работать на большинстве стандартных разновидностей Linux/UNIX. Я не верю, что sh
поддерживает массивы того типа, который рекомендовали другие решения.
Каков наилучший способ выполнить мою команду, поскольку она фактически отображается на экране без дополнительных кавычек, предоставляемых оболочкой?