Команда Bash в строке выполняется, когда я создаю строку, а не когда я использую ее позже

10

Я относительно новичок в написании сценариев оболочки, но почти завершил сценарий, который использует программу lftp . Часть сценария, с которой у меня возникают проблемы, - это создание длинной строки команд (разделенных ;).

for var in something
do
    ...
    commands_to_run+="echo Result is `tail -n 1 $somefile`;"
done

Что я замечаю, так это то, что tailпрограмма, заключенная в обратные метки, запускается, когда цикл for повторяется, а не когда я вызываю строку команд позже в моем скрипте.

К сожалению, содержимое $ somefile на данном этапе не готово для проверки. Как получить команду для выполнения, когда она мне нужна, а не во время создания строки?

Рики
источник

Ответы:

8

Это немного сложно. Информация, предоставленная Хауке, верна, это просто вопрос ее анализа для вашего варианта использования.

Самый простой способ - использовать $()синтаксис, избегая так $, чтобы определение переменной не выполняло команду, заключенную $()в момент определения. Предостережение заключается в том, что конечный результат должен быть повторно оценен (через eval) оболочкой во время фактического выполнения для выполнения вложенной команды.

Гораздо проще взглянуть на пример, поэтому возьмите этот, который должен поставить вас на правильный путь:

for((i=0;i<10;i++)); do 
  date +%s.%N  # Print a timestamp (in format seconds.nanoseconds)
  test="echo \$(date +%s.%N)" # Save a command to do the same
  sleep 1      # Sleep for a second
  eval "$test" # Evaluate the command saved in variable 'test'
  echo         # Print a new line before the next iteration
done

Вот пример выходных данных из примера выше (урезанный до одной итерации):

1398832186.133661344
1398832187.139076728

Вы заметите, что вторая временная метка для каждого цикла составляет около секунды после первой. С другой стороны , если вы выполняете один и тот же тест без возможности избежать $в testопределении и удаления eval, две временные метки будут почти совпадают.

Не привыкать использовать evalв большинстве ситуаций, но это один из тех, где я не знаю, как избежать этого. Надеюсь, это поможет. Удачи!

daBeamer
источник
Большое спасибо, я попробовал использовать, $(...)как предложил Хауке, но обратная косая черта - это ключ.
Рики
Рад, что это помогло - помните, однако, ключ здесь действительно заключается evalв том, что вы можете сделать то же самое, не избегая $и не используя одинарные кавычки ( '), а не двойные кавычки ( "), чтобы окружить вашу команду.
daBeamer
Теперь я только что понял, как и в случае с советами Хуаке, как только я попытаюсь использовать это в программе lftp, echo просто напечатает команду, но фактически не выполнит ее. Возможно, придется попробовать их список рассылки для более конкретной помощи.
Рики
Какую команду вы пытаетесь выполнить? У меня сложилось впечатление, что вам нужна echoстрока с содержимым, включая вывод вложенной команды с отложенным выполнением.
daBeamer
1
@ Рики Я бы согласился со всеми пунктами @HaukeLaging. Код как-минус echoне будет работать, потому что нет команды eval, а есть строка. Если у вас есть более подходящий пример для нас, мы можем попытаться помочь.
daBeamer
6

Есть несколько уровней цитирования. Двойные кавычки ( "...") ЗАЩИТИТЬ пробелы и несколько специальных символов ( ~, &, |, ;, ...) , но не предотвращает подстановка параметров и команд.

Вам нужны либо одинарные кавычки ( '), либо обратная косая черта перед «опасными» символами.

В общем: вы должны рассмотреть возможность использования $(tail ...)вместо обратных галочек. Обратные черты - старый стандарт, но мы говорим о таких старых, которые $()не вызывают проблем у большинства людей. Новая версия легче читается и может быть вложенной. Не говоря уже о проблемах форматирования здесь на SX ...

Хауке Лагинг
источник
Спасибо за быстрый ответ Хауке. К сожалению, замена обратных галочек на рекомендуемые по- $(...)прежнему дает тот же результат - оболочка выполняет это, когда моя строка определена.
Рики
@ Рики Это были не альтернативные предложения. Вы должны использовать, $()но в любом случае вам нужны одинарные кавычки.
Хауке Лагинг
Так что никакая комбинация этих персонажей не достигнет того, что я ищу?
Рики
@Ricky Что так трудно понять о "Вам нужны либо одинарные кавычки"? Вы, очевидно, даже не попробовать.
Хауке Лагинг
На самом деле я так и сделал, но когда я использую одинарные кавычки, эхо просто напечатает все в этой строке как обычную строку. Что такого сложного в том, чтобы привести пример?
Рики