У меня странная ситуация: у меня есть команда, хранящаяся в файле, и этот файл содержит ссылки на переменные.
Я могу нормально прочитать файл, но у меня возникли проблемы с работой расширения переменных.
В качестве минимального рабочего примера, вот файл, содержащий команду с переменной в качестве примера:
ls $DIR
#!/bin/bash
MYVAR=$(<command.in)
DIR = "/tmp"
$MYVAR
Мои ожидаемые результаты заключаются в том, что он напечатает содержимое /tmp.
Я пробовал переместить задание DIR выше задания MYVAR в simple.sh и изменить $DIR в command.in на ${DIR} и $(DIR)
Я думаю тебе нужно eval
@chepner На самом деле я делаю какие-то странные вещи, где я хочу вызвать скрипт после того, как все изображения сгенерированы, но среда еще не разрушена. Я мог бы жестко запрограммировать содержимое сценария в рецепте, но это своего рода антишаблон на тот случай, если сценарий необходимо изменить или мне нужно поделиться этим с другой командой, с которой я работаю. Я все еще мог бы сделать $1 и так далее, но для простоты использования я параметризовал скрипт.
Примечание к стилю: не следует использовать ВЕРХНИЙ РЕГИСТР для переменных Bash. По соглашению верхний регистр зарезервирован для использования в оболочке, например PATH. Пользовательские переменные должны быть в нижнем регистре...
То, что вы сейчас делаете, еще больше противоречит шаблону. command.in на данный момент не параметризован; это то, что я предлагаю вам сделать.
@chepner Я имею в виду, что у меня действительно параметризовано содержимое «реального» содержимого. Он использует getopts и все такое. Чтобы не сделать вопрос слишком конкретным, я не увидел преимуществ содержания. в том, чтобы быть myprog --dir $DIR против ls $DIR. Если вы считаете, что это поможет будущим людям в поиске, я с радостью обновлю его.
Команда, выполняемая command.in, не имеет значения. Дело в том, что вам следует выполнять скрипт с аргументом (command.in "$DIR", который выполняется myprog --dir "$1" с расширением $1 до значения $DIR) вместо того, чтобы пытаться динамически расширить жестко запрограммированное расширение параметра в содержимом command.in.
@SailorCire Возможно, вы правы в своем конкретном случае. Мы с Чепнером комментируем не это. Имейте в виду, что это место предназначено для людей с разным уровнем программирования. Научный, современный, многословный или даже педантичный синтаксис кода будет полезен большему количеству людей, чем что-то, что срезает углы, и потенциально может привить плохую практику новичкам, у которых нет опыта и знаний, чтобы знать, является ли срезание углов для их конкретного варианта использования правильным выбором. .





$(<command.in) разыменовывает переменную. Вы можете увидеть, что происходит, если поставите echo в скрипт:
#!/bin/bash
DIR = "/tmp"
MYVAR=$(<command.in)
echo $MYVAR
$MYVAR
который дает:
bash simple.sh
ls $DIR
ls: cannot access '$DIR': No such file or directory
Когда вы это сделаете $MYVAR, переменная будет расширена один раз. Итак, он производит ls $DIR и вот что выполняется. С помощью eval вы можете принудительно установить другой уровень расширения переменных:
#!/bin/bash
DIR = "/tmp"
MYVAR=$(<command.in)
echo "$MYVAR"
eval "$MYVAR"
Идеальный! использование eval решило проблему. Спасибо! Большинство примеров eval, которые я видел, были чем-то вроде eval $var, и я не знаю разницы между этим и простым вызовом $var напрямую.
Вам все равно нужно взять в кавычки переменные echo "$MYVAR" и eval "$MYVAR".
потребность немного преувеличена; работает без кавычек. Но я согласен: цитировать надо было.
@LjmDullaart, ... это "работает" без кавычек. То есть, похоже, что это работает до тех пор, пока вы не попробуете интересный случай, а затем удивительным образом терпит неудачу.
Например, сравните eval "$code" и eval $code с code=$'printf \' * %s\\n\' *'. И последнее, конечно, намного хуже, чем просто плохой результат, если при запуске в текущем рабочем каталоге есть файл с $(rm -rf ~) как часть его имени.
Просто измените command.in на
ls "$1"
затем выполните его как обычный скрипт (поскольку теперь это обычный параметризованный скрипт).
#!/bin/bash
DIR = "/tmp"
bash command.in "$DIR"
Вам нужно будет использовать
evalдля оценки строки доls <content of $DIR>, прежде чем пытаться выполнить команду. Я бы рекомендовал не определятьcommand.inтаким образом; просто создайте скрипт, который принимает аргумент (ls "$1"), а затем выполнитеcommand.in "$DIR".