我有一个看起来像这样的文件:
$ cat file_test
garbage text A=one B=two C=three D=four
garbage text A= B=six D=seven
garbage text A=eight E=nine D=ten B=eleven
我想遍历每一行并提取要在循环中使用的特定“变量”。而且,如果一行没有变量,则将其设置为空字符串。
因此,对于上面的示例,假设我要提取变量A
,B
和C
,然后对于每一行,循环将具有以下内容:>
garbage text A=one B=two C=three D=four
A
=“一个” B
=“两个” C
=“三个” garbage text A= B=six D=seven
A
=“” B
=“六个” C
=“” garbage text A=eight E=nine D=ten B=eleven
A
=“八” B
=“十一” C
=“” 我最初的计划是使用sed
,但由于“变量”的顺序不一致(例如最后一行),并且可能缺少“变量”(第二行),因此无法使用例如)。
我的下一个想法是逐行浏览,然后使用awk
将行划分为多个字段,并根据每个字段设置变量,但是我不知道从哪里开始或如何开始。
我愿意接受其他想法或更好的建议。
答案 0 :(得分:1)
正确答案取决于您要对变量进行什么处理。
假设您需要将它们作为外壳变量,这是另一种方法
$ while IFS= read -r line;
do A=""; B=""; C="";
source <(echo "$line" | grep -oP "(A|B|C)=\w*" );
echo "A=$A B=$B C=$C";
done < file
A=one B=two C=three
A= B=six C=
A=eight B=eleven C=
诀窍是使用source
来使用grep
从每一行中提取变量声明。由于值分配会继续执行,因此您需要在每行新行之前重置它们。
答案 1 :(得分:0)
在我的前3个解决方案中,我考虑到您需要使用字符串A,B,C
的值中的shell变量,并且您不想简单地打印它们,如果是这种情况,则可能出现以下情况帮助您。
第一个解决方案: :它认为您的变量A,B,C
始终位于相同的字段编号中。
while read first second third fourth fifth sixth
do
echo $third,$fourth,$fifth ##Printing values here.
a_var=${third#*=}
b_var=${fourth#*=}
c_var=${fifth#*=}
echo "Using new values of variables here...."
echo "NEW A="$a_var
echo "NEW B="$b_var
echo "NEW C="$c_var
done < "Input_file"
这只是在每一行中打印变量值,因为您没有告诉您这些变量将被用作什么,所以我只是打印它们,您也可以根据用例来使用它们。
第二个解决方案: :它认为变量以相同的顺序出现,但是它会检查A是否排在第三位,B是否排在第四位或不等,并进行相应打印。
while read first second third fourth fifth sixth
do
echo $third,$fourth,$fifth ##Printing values here.
a_var=$(echo "$third" | awk '$0 ~ /^A/{sub(/.*=/,"");print}')
b_var=$(echo "$fourth" | awk '$0 ~ /^B/{sub(/.*=/,"");print}')
c_var=$(echo "$fifth" | awk '$0 ~ /^C/{sub(/.*=/,"");print}')
echo "Using new values of variables here...."
echo "NEW A="$a_var
echo "NEW B="$b_var
echo "NEW C="$c_var
done < "Input_file"
第三种解决方案: 哪种解决方案可以满足您的要求,但不确定编码副带来的效率(我仍在分析更多是否可以在此处进行其他操作) )。这段代码不会在行中寻找A
,B
或C
的顺序,它将匹配它,让它们在行中的任何地方,如果找到匹配,它将分配变量OR的值否则它将为NULL值。
while read line
do
a_var=$(echo "$line" | awk 'match($0,/A=[^ ]*/){val=substr($0,RSTART,RLENGTH);sub(/.*=/,"",val);print val}')
b_var=$(echo "$line" | awk 'match($0,/B=[^ ]*/){val=substr($0,RSTART,RLENGTH);sub(/.*=/,"",val);print val}')
c_var=$(echo "$line" | awk 'match($0,/C=[^ ]*/){val=substr($0,RSTART,RLENGTH);sub(/.*=/,"",val);print val}')
echo "Using new values of variables here...."
echo "NEW A="$a_var
echo "NEW B="$b_var
echo "NEW C="$c_var
done < "Input_file
输出如下。
Using new values of variables here....
NEW A=one
NEW B=two
NEW C=three
Using new values of variables here....
NEW A=
NEW B=six
NEW C=
Using new values of variables here....
NEW A=eight
NEW B=eleven
NEW C=
EDIT1: :如果您只想打印A,B,C
的值,请尝试执行以下操作。
awk '{
for(i=1;i<=NF;i++){
if($i ~ /[ABCabc]=/){
sub(/.*=/,"",$i)
a[++count]=$i
}
}
print "A="a[1] ORS "B=" a[2] ORS "C="a[3];count=""
delete a
}' Input_file
答案 2 :(得分:0)
如果您选择perl
,请尝试:
perl -ne 'undef %a; while (/([\w]+)=([\w]*)/g) {$a{$1}=$2;}
for ("A", "B", "C") {print "$_=\"$a{$_}\"\n";}' file_test
输出:
A="one"
B="two"
C="three"
A=""
B="six"
C=""
A="eight"
B="eleven"
C=""
它使用=
解析每一行分配,将键值对存储在assoc数组%a
中,最后报告A,B和C的值。
答案 3 :(得分:0)
我偏爱awk
解决方案,例如
$ awk '{for (i = 1; i <= NF; i++) if ($i ~ /^[A-Za-z_][^=]*[=]/) print $i}' file
A=one
B=two
C=three
D=four
A=
B=six
D=seven
A=eight
E=nine
D=ten
B=eleven
说明
for (i = 1; i <= NF; i++)
在每个用空格分隔的字段上循环; if ($i ~ /^[A-Za-z_][^=]*[=]/)
,如果该字段以至少一个字符[A-Za-z_]
开头,后跟'='
;然后print $i
打印字段。答案 4 :(得分:0)
另一个Perl
perl -lne ' %x = /(\S+)=(\S+)/g ; for("A","B","C") { print "$_ = $x{$_}" } %x=() '
包含输入文件
$ perl -lne ' %x = /(\S+)=(\S+)/g ; for("A","B","C") { print "$_ = $x{$_}" } %x=() ' file_test
A = one
B = two
C = three
A =
B = six
C =
A = eight
B = eleven
C =
$
答案 5 :(得分:0)
记录的通用变量awk。
假设变量分隔符是=
,而不是文本前面的部分,也不是变量内容本身。
awk 'BEGIN {
# load the list of variable and order to print
VarSize = split( "A B C", aIdx )
# create a pattern filter for variable catch in lines
for ( Idx in aIdx ) VarEntry = ( VarEntry ? ( VarEntry "|^" ) : "^" ) aIdx[Idx] "="
}
{
# reset varaible value
split( "", aVar )
# for each part of the line
for ( Fld=1; Fld<=NF; Fld++ ) {
# if part is a varaible assignation
if( $Fld ~ VarEntry ) {
# separate variable name and content in array
split( $Fld, aTemp, /=/ )
# put variable content in corresponding varaible name container
aVar[aTemp[1]] = aTemp[2]
}
}
# print all variable content (empty or not) found on this line
for ( Idx in aIdx ) printf( "%s = \042%s\042\n", aIdx[Idx], aVar[aIdx[Idx]] )
}
' YourFile
答案 6 :(得分:0)
尚不清楚您是要设置awk变量还是shell变量,但这是如何填充关联的awk数组,然后使用它来填充关联的shell数组:
$ cat tst.awk
BEGIN {
numKeys = split("A B C",keys)
}
{
delete f
for (i=1; i<=NF; i++) {
if ( split($i,t,/=/) == 2 ) {
f[t[1]] = t[2]
}
}
for (keyNr=1; keyNr<=numKeys; keyNr++) {
key = keys[keyNr]
printf "[%s]=\"%s\"%s", key, f[key], (keyNr<numKeys ? OFS : ORS)
}
}
$ awk -f tst.awk file
[A]="one" [B]="two" [C]="three"
[A]="" [B]="six" [C]=""
[A]="eight" [B]="eleven" [C]=""
$ while IFS= read -r out; do declare -A arr="( $out )"; declare -p arr; done < <(awk -f tst.awk file)
declare -A arr=([A]="one" [B]="two" [C]="three" )
declare -A arr=([A]="" [B]="six" [C]="" )
declare -A arr=([A]="eight" [B]="eleven" [C]="" )
$ echo "${arr["A"]}"
eight