Получить строку из списков переменных в Bash - PullRequest
0 голосов
/ 07 июня 2019

У меня есть файл (file.env), подобный этому:

kw_var1='string1'
kw_var2='string 2'
kw_var3='this is string 3'
kw_var4='does not matter'
kw_var5='maybe'

w_var1=qwert_1
w_var2=qwert_2
w_var3=qwert_3
w_var4=qwert_4

, и мне нужно создать строку list_of_values, которая содержит значения всех переменных, которые начинаются с kw_, т.е.

$ echo -e $list_of_values

должен вывести:

'string1' 'string 2' 'this is string 3' 'does not matter' 'maybe' 

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

list_of_values=$(for param in $(cat $file.env | grep "kw\_"); do echo $(echo -e '$'$param | cut -s -d '=' -f1); done)

но вот что я получаю:

 $kw_var1 $kw_var2 $kw_var3 $kw_var4 $kw_var5

Обратите внимание, что:

  • значения переменных будут содержать пробелы;
  • list_of_values будет использоваться в качестве аргумента для другой функции

Есть идеи, что не так?

ОБНОВЛЕНИЕ:

При выполнении последнего эхаЯ использовал:

$ echo -e $list_of_values | tr '\n' ' '

, чтобы получить все в одну строку.

Ответы [ 5 ]

3 голосов
/ 07 июня 2019

Попытка вашего кода

Я попробовал вашу команду и получу это как вывод:

$kw_var1
$kw_var2

$kw_var3



$kw_var4


$kw_var5

Вы получили неправильный вывод, потому что вы выбрали первое поле, когда выиспользовал cut вместо второго.


Команда фиксации обрезки

for param in $(cat test.txt | grep "kw\_"); do echo $(echo '$'$param | cut -s -d '=' -f2); done

Возвраты:

'string1'
'string
'this


'does

'maybe'

Крепление IFS

Вы использовали цикл for in, но он не перебирает символы новой строки, он перебирает пробелы.Сначала необходимо изменить переменную IFS (Разделитель внутренних полей):

IFS=$'\n'; for param in $(cat <file> | grep "kw\_"); do echo $(echo $param | cut -s -d '=' -f2); done

Вывод:

'string1'
'string 2'
'this is string 3'
'does not matter'
'maybe'

Использование printf

Чтобы получить вывод в одну строку, вы можете использовать printf вместо echo:

for param in $(cat <file> | grep "kw\_"); do printf "$(echo $param | cut -s -d '=' -f2) "; done; printf "\n"

Выход:

'string1' 'string 2' 'this is string 3' 'does not matter' 'maybe' 

Использование while

Вы можете упростить команду и использовать оператор while read, который выполняет итерацию непосредственно по строкам:

cat <file> | grep "kw\_" | cut -d"=" -f2 | while read line; do printf "${line} "; done; printf "\n"

Использование awk

И последнее, но не менее важное: вы можете использовать awk, который значительно упрощает ваш код:

awk -F"=" '/kw_/{printf "%s ", $2}END{print ""}' <file>

Вывод:

'string1' 'string 2' 'this is string 3' 'does not matter' 'maybe'

Если лишний пробел в конце строки раздражает,Вы можете сделать это:

awk -F"=" '/kw_/{printf "%s%s", delim, $2; delim=" "}END{print ""}' <file>

Awk объяснил:

# Using = as delimiter
awk -F"=" '
    # If line contains kw_
    /kw_/{
        # Prints second field
        printf "%s%s", delim, $2;
        delim=" "
    }
    END{
        # Prints newline
        print ""
    }' <file>

Окончательный код

list_of_values=$(awk -F"=" '/kw_/{printf "%s%s", delim, $2; delim=" "}END{print ""}' $file.env)
2 голосов
/ 07 июня 2019
$ cat tst.awk
/^kw_/ {
    sub(/[^=]+=/,"")
    str = str sep $0
    sep = " "
}
END {
    print str
}

например, обратите внимание, что он корректно обрабатывает this=that в нужной выходной строке:

$ cat file
kw_var1='string1'
kw_var2='string 2'
kw_var3='this is string 3'
kw_var4='does not matter'
kw_var5='maybe'
kw_var6='this=that'

w_var1=qwert_1
w_var2=qwert_2
w_var3=qwert_3
w_var4=qwert_4

$ awk -f tst.awk file
'string1' 'string 2' 'this is string 3' 'does not matter' 'maybe' 'this=that'

Обновлено: учитывая то, что вы теперь сказали нам в комментариях, вот как я 'делали бы это, предполагая, что вам иногда нужно обращаться к отдельным значениям по их тегам, в противном случае вы можете использовать обычный массив вместо ассоциативного:

$ cat tst.sh
#!/bin/env bash

declare -A kw
declare -A w
while IFS= read -r line; do
    tag="${line%%=*}"
    val="${line#*=}"
    case "$tag" in
        kw* ) kw["$tag"]="$val" ;;
        w*  ) w["$tag"]="$val" ;;
        ?*  ) printf 'Error: unexpected contents: "%s"\n' "$line"; exit  1;;
    esac
done < file.env

printf '\nAll kw indices => values:\n'
for idx in "${!kw[@]}"; do
    printf '\t%s => %s\n' "$idx" "${kw[$idx]}"
done

printf '\nAll kw values passed to a function (printf) at once:\n'
printf '\t%s\n' "${kw[@]}"

printf '\nAll w indices => values:\n'
for idx in "${!w[@]}"; do
    printf '\t%s => %s\n' "$idx" "${w[$idx]}"
done

printf '\nAll w values passed to a function (printf) at once:\n'
printf '\t%s\n' "${w[@]}"

.

$ ./tst.sh

All kw indices => values:
        kw_var4 => does not matter
        kw_var5 => maybe
        kw_var6 => this=that
        kw_var1 => string1
        kw_var2 => string 2
        kw_var3 => this is string 3

All kw values passed to a function (printf) at once:
        does not matter
        maybe
        this=that
        string1
        string 2
        this is string 3

All w indices => values:
        w_var3 => qwert_3
        w_var2 => qwert_2
        w_var1 => qwert_1
        w_var4 => qwert_4

All w values passed to a function (printf) at once:
        qwert_3
        qwert_2
        qwert_1
        qwert_4

Выше был запущенэтот file.env без лишних одинарных кавычек вокруг значений, в противном случае вы просто удалите их в скрипте:

$ cat file.env
kw_var1=string1
kw_var2=string 2
kw_var3=this is string 3
kw_var4=does not matter
kw_var5=maybe
kw_var6=this=that

w_var1=qwert_1
w_var2=qwert_2
w_var3=qwert_3
w_var4=qwert_4

по наше обсуждение в комментариях и использованиеprintf '<%s>\n' вместо fitsort, которого я не знаю и не имею:

$ list[0]='foo bar'; list[1]='etc'

$ printf '<%s>\n' "${list[@]}"
<foo bar>
<etc>

$ printf '<%s>\n' $(printf '%s\n' "${list[@]}")
<foo>
<bar>
<etc>

$ printf '<%s>\n' "$(printf '%s\n' "${list[@]}")"
<foo bar
etc>

Посмотрите, как первая версия правильно передает содержимое list[] в команду fitsort-replace-replaceв то время как другие передают ей вывод строк через printf?

1 голос
/ 07 июня 2019

Я использовал динамические ссылки.

$: out="$( . file.env; for r in ${!kw_*}; do printf "'%s' " "${!r}"; done; echo )"
$: echo "$out"

'string1' 'string 2' 'this is string 3' 'does not matter' 'maybe'
0 голосов
/ 07 июня 2019

Ваша попытка использует несколько не рекомендуемых практик и содержит несколько синтаксических ошибок:

  • Вы используете $file.env, но это должно быть просто file.env
  • Не используйте for для чтения строк из файла (см. в этой статье )
  • echo $(cmd) - это то же самое, что и cmd плюс глобализация и разбиение по словам, что частоне то, что вы хотите
  • echo -e '$'$param собирается напечатать буквенное $ знак
  • cut -f1 выбирает первое поле, но вы хотите второе поле

Это решение "в духе" того, что вы пробовали, но с использованием только Bash:

list=$(
    while IFS='=' read -r key val; do
        [[ $key == kw_* ]] && printf '%s ' "$val"
    done < file.env
)
list=${list% }   # Remove trailing blank

Если вы имеете дело со строками, содержащими пробелы, обычно рекомендуется использовать массиввместо.Поскольку file.env является действительным Bash, мы можем получить интересующие нас строки и затем построить массив со значениями всех kw_ переменных:

source <(grep '^kw_' file.env)
declare -n var
for var in "${!kw_@}"; do list+=("$var"); done

Массив теперь содержит одну строку наэлемент без буквальных одинарных кавычек:

$ printf '%s\n' "${list[@]}"
string1
string 2
this is string 3
does not matter
maybe

declare -n устанавливает var в nameref: он обрабатывается так, как если бы он действительно был переменной, имя которой он содержит.Для этого требуется Bash 4.3 или новее.

0 голосов
/ 07 июня 2019

Создайте два массива из вашей группы переменных, затем вы можете легко перебирать их, как это

#!/bin/bash

kw=(
'string1'
'string 2'
'this is string 3'
'does not matter'
'maybe'
)

w=(
'qwert_1'
'qwert_2'
'qwert_3'
'qwert_4'
)

for i in {1..5}
do
    echo -n "\"${kw[$i]}\" "
done

echo

for i in {1..4}
do
    echo -n "\"${w[$i]}\" "
done

echo
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...