我有一个文件,像
water
{
nu 1.69e-3;
rho 8;
}
vapour
{
rho 2;
}
right
{
type zeroGradient 6;
value uniform (40 10 0);
}
left
{
value uniform (0 5 0);
}
,我想从中提取1.69e-3
,8,2
,40
,5
值,并将这些值分别保存在变量中。要提取8
和2
并将它们保存到变量中,我使用以下命令
rhol=`grep rho file | awk '{print $NF}' | sed -e 's/;//g' | head -1`
rhog=`grep -m2 rho file | awk '{print $NF}' | sed -e 's/;//g' | tail -n1`
但要获得1.69e-3
的科学值,以及40
和5
的另外两个值,我有问题,以获得这些值。
Using Bash 4/Associative Array/awk
#!/bin/bash
reformatText(){
# format input text to [parent_key,child_key]="value"
awk '
/{|}/ {next}
!/^ / {parent_key=$1; next}
{
child_key=$1; $1=""; gsub(/^ |;|)|(/,"")
if(child_key=="value"){
for (i=1; i<=NF; i++)
printf "[%s,%s,%s]="%s"n", parent_key, child_key, i, $i
}else{
printf "[%s,%s]="%s"n", parent_key, child_key, $0
}
}
' input_file
}
arrayValues="$(reformatText)"
declare -A myArray="($arrayValues)"
echo "${myArray[water,nu]}"
echo "${myArray[vapour,rho]}"
echo "${myArray[water,rho]}"
echo "${myArray[right,value,2]}"
echo "${myArray[left,value,3]}"
输出:
1.69e-3
2
8
40
5
重新格式化文本:
[water,nu]="1.69e-3"
[water,rho]="8"
[vapour,rho]="2"
[right,type]="zeroGradient 6"
[right,value,1]="uniform"
[right,value,2]="40"
[right,value,3]="10"
[right,value,4]="0"
[left,value,1]="uniform"
[left,value,2]="0"
[left,value,3]="5"
[left,value,4]="0"
数组内容:
declare -A myArray=([right,type]="zeroGradient 6" [right,value,2]="40" [right,value,3]="10" [right,value,1]="uniform" [right,value,4]="0" [left,value,1]="uniform" [left,value,3]="5" [left,value,2]="0" [left,value,4]="0" [vapour,rho]="2" [water,nu]="1.69e-3" [water,rho]="8" )
不带数组的第二种方法
reformatText2(){
# format input text to parent_key,child_key,...="value"
awk '
/{|}/ {next}
!/^ / {parent_key=$1; next}
{
child_key=$1; $1=""; gsub(/^ |;|)|(/,"")
if(child_key=="value"){
for (i=1; i<=NF; i++)
printf "%s_%s_%s="%s"n", parent_key, child_key, i, $i
}else{
printf "%s_%s="%s"n", parent_key, child_key, $0
}
}
' input_file
}
source <(reformatText2)
echo "${water_nu}"
echo "${water_rho}"
echo "${vapour_rho}"
echo "${right_value_2}"
echo "${left_value_3}"
输出1.69e-3
8
2
40
5
显示所有赋值
reformatText2
water_nu="1.69e-3"
water_rho="8"
vapour_rho="2"
right_type="zeroGradient 6"
right_value_1="uniform"
right_value_2="40"
right_value_3="10"
right_value_4="0"
left_value_1="uniform"
left_value_2="0"
left_value_3="5"
left_value_4="0"
这是一个简单的Awk解析器,它输出您可以eval
的分配。在实际操作之前,您需要非常确定输出是您所期望的。
awk 'BEGIN { insec=0 }
/[^{]/ && NF==1 && !insec { sec=$1; next }
/[{]/ && sec { insec=1; next }
/[}]/ && insec { sec=""; insec=0; next }
insec && !/^[ t]*(value|type)/ && NF>1 { sub(/;$/, ""); printf "%s_%s=%sn", sec, $1, $NF }
insec && /^[ t]*value/ { gsub(/[();]+/, ""); for(i=3; i<=NF; i++) printf "%s_%i=%sn", sec, i-2, $i }' "$@"
另存为脚本;在文件上运行它应该产生类似
的内容water_nu=1.69e-3
water_rho=8
vapour_rho=2
right_1=40
right_2=10
right_3=0
left_1=0
left_2=5
left_3=0
根据评论中的要求,这将uniform
字段拆分为单独的值left_1
,left_2
等。(但实际上,请确保您的问题本身是完整和定义良好的。评论可随时删除
一旦结果是你想要的,你可以像
那样运行它eval "$(yourscript yourfile)"
让shell计算它输出的赋值。
演示:https://ideone.com/hGPsTE
与以往一样,在实际使用eval
之前要非常谨慎。也许有更好的方法来完成你的要求;如果可行的话,我建议在Awk中也实现其余的逻辑。
这是我认为你想从看你的样本:
- 没有单词uniform的行,行中的数字(
;
之前的数字)。 - 线均匀,括号之间的数量(s),如果不是等于0。
你可以awk
:
/uniform/ {
numbers = gensub(/.*((.*));/, "\1", "g", $0)
split(numbers, numbersarray, " ")
for (i in numbersarray) {
if (numbersarray[i] != 0) {
print numbersarray[i]
}
}
}
/;$/ && ! /zeroGradient;/ {
t=length($2)
print substr($2,0,t-1)
}
保存到file.awk
并使用awk -f file.awk inputfile.txt
运行
为行/uniform/
- 提取数字。它们是在
( )
之间看到的。这里使用gensub
,它的工作原理与sed 's///'
相似。(
是在文本中找到的,(
是用来定义以后使用的\1
的值。 - 然后将数字字符串拆分为数组。
- 循环,任何!= 0的数字都会被打印到屏幕上。
gensub
details:
/.*((.*));/
//
delimate a pattern.*
将匹配任何(0或更多的任何字符)(
uniform
后面的括号);
与;
的右括号(.*)
括号之间的任何内容,并在字段no中设置。1为更换。
对于以;
结尾的行而不是以zeroGradient
结尾的行
- 打印该行的第二个字段,删除末尾的
;
。
使用它的输出是:
1.69e-3
8
2
40
5