заменить переменные, когда я кошка файла - PullRequest
3 голосов
/ 17 мая 2011

Возможно ли чистым способом получить значения переменных, когда я котирую файл, вместо имен переменных, как написано в файле. Это сложно объяснить, но вот простой пример:

$ cat <<EOF
$HOME
EOF
/home/myself

cat возвращает / home / себя, потому что она уже развернута оболочкой.

$ echo \$HOME >/tmp/home
$ cat /tmp/home
$HOME

cat просто читает файл, я хочу, чтобы $ HOME здесь каким-то образом расширился cat, потому что файл будет содержать имена переменных (не как HOME = / home /self)

Мой вопрос: возможно ли это как-нибудь, иначе мне придется написать какой-нибудь грязный код.

РЕДАКТИРОВАТЬ: это большие XML-файлы, содержащие

<checkbox active="$value">

истина или ложь

Ответы [ 3 ]

2 голосов
/ 17 мая 2011

Это было бы тривиально, чтобы попытаться в Python, и посмотреть, если это работает для вас.Вы можете использовать функцию re.sub для замены всех вхождений некоторого шаблона, такого как "\$\w+", вызывая функцию, которая выполняет преобразование (а не конкретную строку для ее замены).А для функции замены вы можете использовать os.getenv(), которая, конечно же, принимает имя переменной и возвращает ее значение.

Редактирование: Вот полный скрипт Python, который выполняет вышеуказанное:

#!/usr/bin/python

import fileinput
import os
import re

def transform(match):
    return os.getenv(match.group(1)) # replace the "capture" to omit $

for line in fileinput.input(): # reads from stdin or from a file in argv
    print re.sub('\$(\w+)', transform, line), # comma to omit newline
1 голос
/ 17 мая 2011

Очевидный способ сделать это имеет много проблем:

# This will fail with certain inputs.  HTML will certainly be a problem
# as the '<' and '>' characters will be interpreted as file redirects
$ while read r; do eval echo $r; done < input

Следующий perl должен справиться с проблемой достаточно просто для простых входных данных.

$ perl -pwe 'while(($k,$v) = each %ENV ) { s/\${?$k}?/$v/ }' input

Но это не такничего не делать с такими конструкциями, как $ {FOO-bar}.Если вам нужно обработать такие конструкции, может быть достаточно экранировать все метасимволы оболочки и выполнить цикл while / read:

$ sed -e 's/\([<>&|();]\)/\\\1/g' input | while read -r l; do eval echo "$l"; done

Обратите внимание, что это не является ни надежным, ни безопасным.Посмотрите, что происходит на входе, как:

\; rm -rf /

Я сказал «рассмотреть».Не проверяйте это.Sed вставит обратную косую черту перед точкой с запятой, тогда eval получит строку "\\;"который будет интерпретирован как одиночная обратная косая черта, за которой следует точка с запятой, которая завершает эхо, и будет выполнен rm -rf.Учитывая небезопасную оценку неизвестных входных данных, вероятно, было бы безопаснее придерживаться чего-то вроде perl и явно заменять нужные конструкции sh.Примерно так:

$ perl -pwe 'while(($k,$v) = each %ENV ) { s/\${?$k}?/$v/ }; 
    s/\${[^-]*-([^}]*)}/$1/g' input

У этого проблемы с вводом, например $ {FOO = some-text}.Чтобы надежно получить все конструкции sh ($ {word: rhs}, где ':' может быть любым из '-', '?', '=', '+', '%', '#' Илилюбой из них с предваряющим двоеточием (или множеством других символов, если вы разрешите синтаксис non-posix sh!)) вам придется создать довольно сложный набор сравнений.

1 голос
/ 17 мая 2011

cat копирует свои входные данные без изменений в свои выходные данные - по крайней мере, в исходном виде (1-е издание UNIX).У него не было вариантов для начала.Затем BSD добавил группу, и первоначальная команда UNIX возразила: «cat вернулся из Беркли, размахивая флагами» (см .: 1 - passim).Он не должен использоваться для редактирования файлов - это не его цель.(Я нашел ссылку на статью в справочной странице BSD (Mac OS X) для cat: Роб Пайк, "Стиль UNIX, или cat -v считается вредным" , Материалы USENIX Summer Conference Proceedings, 1983См. Также http://quotes.cat -v.org /рограммирование / )

Итак, вам нужно что-то отличное от cat для выполнения этой работы.Я бы порекомендовал Perl или Python;любой может сделать это довольно легко.В качестве альтернативы рассмотрим sed, или, возможно, awk.

#!/usr/bin/env perl
use strict;
use warnings;
while (<>)
{
    foreach my $key (keys %ENV)
    {
        s/\$$key\b/$ENV{$key}/g;  # $envvar
        s/\${$key}/$ENV{$key}/g;  # ${envvar}
    }
    print;
}

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

#!/usr/bin/env perl
use strict;
use warnings;
while (<>)
{
    while (m/\$((\w+))/ || m/\$({(\w+)})/)
    {
        my $key = $2;
        my $var = $1;
        s/\$$var/$ENV{$key}/g if defined $ENV{$key};
    }
    print;
}

Когда я включил литерал $ в захваты, операция замены не работала правильно.

...