2

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

awk -v var1="$var1" -v var2="$var2" -v var3="$var3" ....... '
    # awk code
' 

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

$(awkline var1 var2 var3 ......) '
   # awk code
'

где вывод команды "awkline" - правильный формат команды awk. Например, программа "awkline" может выглядеть так:

#!/bin/bash
line="awk"
for i in $*; do line="$line -v $i="'"$'"$i"'"'; done
echo $line

Если я затем запустил "awkline ab c", я получу то, что ожидаю:

awk -v a="$a" -v b="$b" -v c="$c"

Однако, если я попытаюсь выполнить команду, подобную $(awkline abc), значение переменной a внутри awk становится (буквально включая кавычки) «$ a», а не значением a, как мне бы хотелось. Как заменить все вхождения, например, $ a, значением переменной a, чтобы я мог запустить команду awkline?

1 ответ1

2

Не делайте awkline отдельным скриптом: это означает, что вам придется экспортировать все переменные, которые вы хотите передать в awk. Вы можете сделать это функцией, которую добавляете в свой .bashrc. Таким образом, он запускается в текущем процессе оболочки и имеет доступ к переменным вашей оболочки.

Обработка параметров будет непростой задачей: вы можете:

  1. передайте переменные в виде строки, разделенной пробелом, и укажите переменное число аргументов файла:

    awkline "var1 var2 var3" "awk body" file ...
    
  2. или иметь функцию, всегда читающую из стандартного ввода и разрешающую переменное число имен переменных:

    cat file1 file2 ... | awkline var1 var2 ... "awk body"
    

Для кодирования первого:

awkline () {
    local variables=$1
    local body=$2
    shift 2
    local files=("$@")

    set -- $variables   # no quotes here, now the positional params are the var names
    local awk_cmd=(awk)
    for var; do
        awk_cmd+=(-v "$var=${!var}")
    done

    "${awk_cmd[@]}" "$body" "${files[@]}"
}     

Учитывая использование в вашем комментарии, это может быть упрощено:

awkline () {
    local awk_vars=()
    for var in $1; do                   #  no quotes here
        awk_vars+=(-v "$var=${!var}")
    done
    shift
    awk "${awk_vars[@]}" "$@"
}     

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .