#bash #shell
#bash #оболочка
Вопрос:
Я не понимаю, почему это работает
dateCMD=$(date -d "4 hours ago")
echo $dateCMD
Tue Oct 18 02:20:34 AEDT 2016
и это работает
dateCMD="date"
$dateCMD
Tue Oct 18 06:23:19 AEDT 2016
Но не это
dateCMD='date -d "4 hours ago"'
$($dateCMD)
date: extra operand ‘ago"’
Как я могу заставить этот последний случай работать?
Комментарии:
1. Я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу!
Ответ №1:
Короткий ответ: вы не хотите этого делать. Вместо этого используйте функцию.
dateCMD () {
date -d "4 hours ago"
}
dateCMD
Длинный ответ: кавычки в значении параметра не являются «синтаксическими» кавычками; это просто обычные данные. Когда вы пишете
dateCMD='date -d "4 hours ago"'
$($dateCMD)
Он оценивается следующим образом:
$dateCMD
расширяется доdate -d "4 hours ago"
- Расширение разбито на слова
date
,-d
,"4
,hours
, иago"
. Кавычки не обрабатываются специально. - Первое слово,
date
, обрабатывается как команда, а остальные слова передаются как отдельные аргументы. date
используется"4
в качестве аргумента для-d
параметра. Посколькуdate
принимает только один дополнительный позиционный аргумент (строку формата), он принимаетhours
в качестве этого аргумента, а затем жалуется, чтоago
это дополнительный операнд.
Комментарии:
1. Хорошее объяснение, почему это не работает, спасибо. Я также понял
eval
, что это сработает (с очевидными оговорками безопасности), и ответ anubhava на array был интересным.
Ответ №2:
Используйте массив BASH, чтобы заставить его работать:
dateCMD=(date -d "4 hours ago")
"${dateCMD[@]}"
Mon Oct 17 11:38:54 EDT 2016
Я печатал объяснение вашей проблемы с цитированием, но затем я заметил очень хорошо объясненный ответ от @chepner, поэтому избегал добавления избыточной информации в мой ответ.
Комментарии:
1. Интересное решение для bash 4. Спасибо. Я также обнаружил
eval
, что это сработает.2. Это должно работать не только с BASH 4, но и с BASH 3.2.
3. Вы правы. Я не понимал, что массивы также можно использовать в Bash 3.2, спасибо.
Ответ №3:
Чтобы заставить последний случай работать, вы можете использовать eval
Конечно, вы не должны использовать eval для любого пользовательского ввода без полной проверки этого ввода.
dateCMD='date -d "4 hours ago"'
eval $dateCMD