将awk(索引搜索)输出保存在shell变量中(返回值除外)

时间:2018-11-27 11:03:55

标签: bash shell awk sed

请考虑以下情形:

echo 52=abcd_53=1_54=efgh_55=ijkl | awk -v time_tag="52=" -v start_time="54=" -v end_time="55=" '{p=index($0, time_tag)} {q=index($0, start_time)} {r=index($0, end_time)} /53=1/'

我想在shell变量中获取p,q,r的值,以便在执行上述命令后可以使用它们。 我无法使用shell数组,因为最终目标如下:

for line in $(cat $dir/$file | awk '/53=1')
do
    for word in $(echo $line | tr "_" "\n")
    do
        if [ ${word:0:3} == "52=" ] ; then
            time_tag=$word
        elif [ ${word:0:3} == "54=" ] ; then
            start_time=$word
        elif [ ${word:0:3} == "55=" ] ; then
            end_time=$word
        fi
    done
    echo $time_tag","$start_time","$end_time
done

我希望将以上执行更改为以下执行,以期更快执行:

for line in $(cat $dir/$file | awk -v time_tag="52=" -v start_time="54=" -v end_time="55=" '{p=index($0, time_tag)} {q=index($0, start_time)} {r=index($0, end_time)} /53=1/')
do
    echo ${line:p:7}","echo ${line:q:7}","echo ${line:r:7}
done

我认为,如果我只是在awk行本身中获取索引,由于时间是一个瓶颈,因此程序可以变得更快(数百万行)。

2 个答案:

答案 0 :(得分:0)

除返回值之外的其他,不是,但是如何消除无用的cat和:

$ cat file
52=abcd_53=1_54=efgh_55=ijkl
$ for i in file
  do 
    ret=$(awk -v time_tag="52=" -v start_time="54=" -v end_time="55=" '{p=index($0, time_tag)} {q=index($0, start_time)} {r=index($0, end_time)} /53=1/{print p,q,r}' "$i")
    read -r -a array <<< "$ret"
  done
$ echo ${array[0]}
1
$ echo ${array[1]}
14
$ echo ${array[2]}
22

awk部分最后改变了一点:

awk -v time_tag="52=" -v start_time="54=" -v end_time="55=" '{
    p=index($0, time_tag)
} 
{
    q=index($0, start_time)
} 
{
    r=index($0, end_time)
} 
/53=1/ {
    print p,q,r  # added this and the brackets around this
}' $i

现在awk输出:

1 14 22

arrayread上的空间分割。

在不知道文件中包含什么以及预期输出是什么样的情况下,我真的无法做更多的事情(即,用awk完全重写它)。

答案 1 :(得分:0)

您的问题尚不清楚,但是根据您的原始脚本,我认为以下输入内容

52=abcd_53=1_54=efgh_55=ijkl

应返回以下输出:

52=abcd,54=efgh,55=ijkl

如果这是您的最终目标,则可以执行以下awk:

awk 'BEGIN{FS="[_=]";OFS=","}
     { for(i=1;i<NF;i+=2) a[$i]=$i"="$(i+1)
       if(a[53]==1) print a[52],a[54],a[55]
       delete a
     }' file

当然,这假定您的所有行都是这样。

如果要使用bash脚本处理类似的事情,则可以使用while循环直接处理此输出

awk '{...}' file | while IFS=, read -r time_tag start_time end_time; do
   do what you want to do
done

如果要快速执行,请使用awk进行所有操作,并将其输出传递到bash循环: