从文件中提取不同类型的数据,并将这些值保存在变量中



我有一个文件,像

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值,并将这些值分别保存在变量中。要提取82并将它们保存到变量中,我使用以下命令

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的科学值,以及405的另外两个值,我有问题,以获得这些值。

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的数字都会被打印到屏幕上。

gensubdetails:

  • /.*((.*));/
  • //delimate a pattern
  • .*将匹配任何(0或更多的任何字符)
  • (uniform后面的括号
  • );;
  • 的右括号
  • (.*)括号之间的任何内容,并在字段no中设置。1为更换。

对于以;结尾的行而不是以zeroGradient结尾的行

  • 打印该行的第二个字段,删除末尾的;

使用它的输出是:

1.69e-3
8
2
40
5

最新更新