2014-09-04 3 views
1

Я имею текстовую строку в переменной в Баш, которая выглядит следующим образом:Подстановка переменных в виде текстовой строки

filename1.txt 
filename2.txt 

varname1 = v1value 
$(varname1)/filename3.txt 
$(varname1)/filename4.txt 

varname2 = $(varname1)/v2value 
$(varname2)/filename5.txt 
$(varname2)/filename6.txt 

Я хочу, чтобы заменить все переменные в месте, производя это:

filename1.txt 
filename2.txt 

v1value/filename3.txt 
v1value/filename4.txt 

v1value/v2value/filename5.txt 
v1value/v2value/filename6.txt 

Может ли кто-нибудь предложить чистый способ сделать это в оболочке?

+0

Насколько велик этот файл? Это та проблема, которую на самом деле быстрее решить вручную, с хорошим текстовым редактором, если файл действительно большой. – slezica

+0

Это всего лишь образец. На самом деле существует несколько сотен файлов, таких как у каждого из них между нулями и 20 подстановками. – user2664470

ответ

1

Я нашел разумное решение, используя m4:

function make_substitutions() { 
    # first all $(varname)s are replaced with ____varname____ 
    # then each assignment statement is replaced with an m4 define macro 
    # finally this text is then passed through m4 

    echo "$1" |\ 
    sed 's/\$(\([[:alnum:]][[:alnum:]]*\))/____\1____/' | \ 
    sed 's/ *\([[:alnum:]][[:alnum:]]*\) *= *\(..*\)/define(____\1____, \2)/' | \ 
    m4 
} 
+0

Вы можете использовать этот же шаблон с любым языком или шаблоном/макросистемой, который позволяет такую ​​оценку времени выполнения. Вы могли бы даже сделать это с помощью оболочки с некоторыми усилиями (и санитацией). Решение (однопроходное) awk также должно быть довольно простым. –

0

Пожалуй

echo "$string" | perl -nlE 'm/(\w+)\s*=\s*(.*)(?{$h{$1}=$2})/&&next;while(m/\$\((\w+)\)/){$x=$1;s/\$\($x\)/$h{$x}/e};say$_' 

печатает

filename1.txt 
filename2.txt 

v1value/filename3.txt 
v1value/filename4.txt 

v1value/v2value/filename5.txt 
v1value/v2value/filename6.txt 
2

В AWK:

BEGIN { 
    FS = "[[:space:]]*=[[:space:]]*" 
} 

NF > 1 { 
    map[$1] = $2 
    next; 
} 

function replace( count) 
{ 
    for (key in map) { 
     count += gsub("\\$\\("key"\\)", map[key]) 
    } 

    return count 
} 

{ 
    while (replace() > 0) {} 
    print 
} 

В Lua:

local map = {} 

--for line in io.lines("file.in") do -- To read from a file. 
for line in io.stdin:lines() do -- To read from standard input. 
    local key, value = line:match("^(%w*)%s*=%s*(.*)$") 
    if key then 
     map[key] = value 
    else 
     local count 
     while count ~= 0 do 
      line, count = line:gsub("%$%(([^)]*)%)", map) 
     end 
     print(line) 
    end 
end 
Смежные вопросы