Проанализируйте файл с помощью BASH-скрипта и скопируйте шаблон, соответствующий переменной

#regex #parsing #bash #variables

#регулярное выражение #синтаксический анализ #bash #переменные

Вопрос:

Допустим, у меня есть файл (php, как это бывает) с несколькими объявлениями переменных:

 $dbuser = 'fred';
$dppass = 'abc123';
$dhhost = '127.0.0.1';
  

Что я хочу сделать с помощью BASH-скрипта, так это проанализировать этот файл, определить нужные мне переменные и прочитать их значения в переменные, к которым я могу получить доступ из моего BASH-скрипта.

Очевидно, что приведенный выше файл, являющийся PHP, содержит другие строки, которые меня не интересуют.

Я могу извлечь нужную мне информацию из оболочки bash, используя следующую команду:

 grep $dbuser config.php.inc | grep -Po "'.*'" | cut -d ' -f 2
  

который аккуратно возвращает

 fred
  

Но когда я пытаюсь добавить это в bash-скрипт, чтобы поместить выходные данные в переменную, используя обратные ссылки, следующим образом:

 dbuser=`grep $dbuser config.php.inc | grep -Po "'.*'" | cut -d ' -f 2`
  

на этом этапе мой BASH-скрипт зависает.

Почему это зависает, или есть ли лучший способ сделать то, чего я пытаюсь достичь?

Ответ №1:

Попробуйте это таким образом:

 dbuser=$(grep $dbuser config.php.inc | grep -Po "'.*'" | cut -d ' -f 2)
  

Причина, по которой это работает, а обратные подсказки — нет, заключается в том, как $ (command) обрабатывает цитирование по сравнению как обратные ссылки старого стиля обрабатывают цитирование.

Другими словами, следующая команда возврата сработала бы так же хорошо:

 dbuser=`grep '$dbuser' config.php.inc | grep -Po "'.*'" | cut -d"'" -f 2`
  
  1. Использовал одинарные кавычки, чтобы заключить $dbuser, поскольку одинарные кавычки означают использование буквального текста, а не интерполяцию его как переменной оболочки.
  2. Удалено экранирование из .* поскольку оно не требуется.
  3. Удалено экранирование из команды cut, поскольку оно не требуется.

Кстати, это бы тоже сработало:

 dbuser=`grep '$dbuser' config.php.inc | grep -Po "'.*'" | cut -d ' -f 2`
  

Кроме того, синтаксис $ (command) в целом является наилучшим подходом, когда это возможно. Используйте ` только из соображений переносимости, если вам необходимо поддерживать платформу, которая, как абсолютно точно известно, не поддерживает $ (command). Это, ИМХО, очень редко, поэтому эмпирическое правило — с самого начала ориентироваться на $ (command).

Комментарии:

1. Можете ли вы объяснить, почему это работает? Я думаю, что это действительно работает, но это очень тонко.

2. Это лучший метод, чем использование обратных ссылок?

3. По сути, да, $ (command) — лучший и более современный подход. Используйте обратные ссылки только тогда, когда вам нужно поддерживать платформу, которая, как известно, не поддерживает $ (command), что редко встречается в наши дни. Обратные ссылки имеют проблемы с менее чем тривиальным цитированием и действительно падают, когда вам нужно поддерживать несколько уровней вложенных команд. $ (command) хорошо справляется с этим.

4. Большое спасибо за объяснение, я не знал об этом и просто всегда использовал обратные ссылки. Я хотел бы, чтобы я мог принять все ответы на данный момент на вопрос, поскольку каждый из них предоставляет правильное решение.

Ответ №2:

Это вернет текст, подобный var='value';

 awk '
    match($1, /^$([[:alnum:]_] )=?/, m){
        gsub(/^[^=] =[[:space:]]*/, "")
        print m[1] "=" $0
    }
' < file.php
  

Вы можете eval получить результат.

Обновить

Это намного проще, чем описано выше. Я понял, что все, что вам нужно сделать, это удалить первое $ и убрать пробелы вокруг = :

 sed -e 's/$//' -e 's/ *= */=/' file.php
  

Комментарии:

1. Вау! Это аккуратный способ сделать это. Произойдет сбой в строке, которая вызывает функцию mysql_connect $db=mysql_connect(... , но я могу легко переключить это на другое включение, чтобы обойти это.

2. … и под ошибкой я подразумеваю, что eval часть завершится неудачей.

3. sed Версия работает не совсем так хорошо, поскольку она не справляется с другими строками в файле. К ним относятся <?php , ?> и строки комментариев, ini_set , require_once а также несколько других строк, специфичных для PHP.

4. Принято на основе awk-части ответа, поскольку она касается всех переменных в моем config.php.inc, без необходимости жестко кодировать каждую переменную.

5. @Брайан, я переходил к вашему образцу кода, который показывал только объявления переменных. Рад, что версия awk все же сработала для вас.

Ответ №3:

Похоже, что отсутствует

Проверьте, не \ $dbuser

Если у вас есть доступ к perl, попробуйте:

 dbuser=$(perl -ne "print $1 if /$dbuser.*'(.*)'/" config.php.inc)
  

Примечание :
-e используйте следующий параметр как однострочный скрипт
-n используйте все параметры в качестве аргумента файла

выведите $ 1 распечатайте соответствующий шаблон при совпадении
Паратезис в регулярном выражении определяет группу захвата в 1 доллар.

Комментарии:

1. Добавление второго управляющего символа устранило проблему. На данный момент у меня нет доступного perl, но я мог бы попробовать. Определяет ли скобка ту часть, которая выводится из match?

Ответ №4:

С некоторой базовой проверкой и безопасностью

 eval $(sed -n "s/^$([a-zA-Z][a-zA-Z0-9_]*) *= *'(.*)' *;/1='2';/p")
echo User:$dbuser Pass:$dppass Host:$dhhost
  

выведет для вашего примера

 User:fred Pass:abc123 Host:127.0.0.1