我有一个与此相似的文件(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' ' '
将所有内容集中在一起。
答案 0 :(得分:3)
尝试输入代码
我尝试了您的命令,并将其作为输出:
$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 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)
答案 1 :(得分:2)
$ 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
wrt our discussion in the comments并使用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-replacement命令,而其他版本则将printf输出的字符串传递给它吗?
答案 2 :(得分:1)
我使用了动态引用。
$: 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'
答案 3 :(得分:0)
将一堆变量组成两个数组,然后您可以像这样轻松地对其进行迭代
#!/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
答案 4 :(得分:0)
您的尝试使用了一些不推荐的做法,并且包含一些语法错误:
$file.env
,但应该只是file.env
for
从文件中读取行(请参见this article)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或更高版本。