Word не расширяется в команду оболочки в bash

Может ли кто-нибудь помочь в этом:

Я хочу выполнить некоторые команды в сценарии оболочки, прочитав их из другого текстового файла примерно так:

command_file.txt содержит:

EXECUTED_OK_$(date)
EXECUTED_OK_$(hostname)

оболочка script.sh

#!/bin/sh

while read command
do
echo $command 
done < command_file.txt

Моя проблема в том, что эхо печатает как текст, как в командном файле. Как я могу расширить его и напечатать фактическую дату и имя хоста.

Например Ожидаемый результат должен быть:

EXECUTED_OK_22-02-2010 11:10:10
EXECUTED_OK_localhost

Но я получаю:

EXECUTED_OK_$(date)
EXECUTED_OK_$(hostname)

Рассмотрите envsubst, если это доступно.

bishop 21.05.2019 21:23

Поведение, которое вы видите, является желательным и соответствует спецификации. Если бы данные были расширены как код «за вашей спиной», было бы практически невозможно написать код, обрабатывающий ненадежные данные в bash.

Charles Duffy 21.05.2019 21:40

(опять же, вы в основном просим, ​​чтобы ваши данные должны выполняться как код, для чего и предназначен eval. Это также общая плохая идея, и ее лучше избегать, но... ну, это является то, о чем вы просите).

Charles Duffy 21.05.2019 21:43

@Charles Duffy Если мы рассмотрим ситуацию, в которой нам нужно создавать динамические команды во время выполнения, это может быть проще, чем запускать отдельные команды и объединять окончательный вывод.

Dark Matter 21.05.2019 21:50

...но если вам нужен эффект eval, почему вы на самом деле не с использованиемeval? Это плохая практика, но это потому, что вещь, которую он выполняет (нарушение границы между данными и кодом) является плохой практикой. Вы активно просите об этом (чтобы оценить ваши данные как код, полагая, что его содержимое будет безопасным для выполнения), так что вы можете использовать его, если вы действительно, В самом деле уверены, что это то, что вы хотите.

Charles Duffy 21.05.2019 21:50

@Charles Duffy, вот почему я сейчас использую функциональный подход, я подумал, что может быть какой-то обходной путь для этой ситуации, кроме eval

Dark Matter 21.05.2019 22:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
148
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

Программа заменяет определенные внешние ссылки в каждой команде вашего командного файла их выходными данными перед печатью команды:

#!/bin/bash

while read command
do
    while read -a external ; do
        output=$( "${external[@]}" )
        command=$( sed "s/\$(${external})/${output}/g" <<< "$command" )
    done <<END
    date -R
    hostname
END
    echo "$command"
done < command_file.txt

Чтобы использовать больше внешних элементов, вам нужно добавить их в документ между <<END и END. Я добавил -R к date, чтобы продемонстрировать внешний вид с аргументами.

Как было указано, никакая обработка (например, кавычки, замены), кроме разделения слов, не будет выполняться для внешних команд (пробелы можно экранировать (one\ two) вместо кавычек).

$($anything) не полностью эквивалентен $(eval "$anything"); см. БашFAQ #50.
Charles Duffy 21.05.2019 21:49

...аналогично, read -a external не обрабатывает кавычки и т.д. так же, как и синтаксический анализ оболочки, поэтому простое сокращение до "${external[@]}" на самом деле не исправляет случаи, не указанные в кавычках $anything, становится неправильным. (Попробуйте touch 'hello world' в качестве примера; разделение строк без кавычек приведет touch к созданию двух отдельных файлов, 'hello и world').

Charles Duffy 21.05.2019 22:01

@CharlesDuffy Спасибо, это не сработало бы с аргументами. Я изменил свой пример, чтобы использовать массив.

Michael Jaros 21.05.2019 22:01

используйте eval, чтобы расширить переменные и выполнить его повторно.

$ foo='EXECUTED_OK_$(date)'
$ echo $foo
EXECUTED_OK_$(date)
$ eval "echo $foo"
EXECUTED_OK_Tue May 21 12:39:45 PDT 2019

Обновлено: eval мощный, но может быть опасным; это в основном инъекция кода. Цитирование аргументов — хорошая идея; см. комментарии ниже для получения дополнительных объяснений.

eval "echo $foo" немного меньше ошибок (или, по крайней мере, немного меньше вводит в заблуждение о том, как это работает). Если вы запускаете eval echo $foo без кавычек, когда foo='*', например, вы заменяете * списком имен файлов, запускается доeval, что делает его поведение почти невозможным предсказать без знания этих имен.
Charles Duffy 21.05.2019 21:41

(Если у вас есть foo='*'; eval echo $foo, вам лучше надеяться, что никто не создал файл с touch '$(rm -rf ~)'; тогда как с foo='*'; eval "echo $foo"* расширяется послеeval, поэтому имена файлов, в которые он расширяется, не могут быть выполнены как код).

Charles Duffy 21.05.2019 21:57

Кстати, см. БашПитфоллы #14 обсуждение того, почему цитировать даже в echo "$foo" — хорошая идея.

Charles Duffy 21.05.2019 22:05

Один из вариантов - использовать eval, предполагая, что вы доверять входной файл

#!/bin/sh

while read command; do 
  eval "echo $command" 
done < command_file.txt

Другие вопросы по теме