Unix文件模式问题:将变量模式的值更改为匹配行的副本

时间:2016-10-04 13:54:28

标签: shell unix ksh

我有一个包含内容的文件:

abc|r=1,f=2,c=2
abc|r=1,f=2,c=2;r=3,f=4,c=8

我想要一个如下结果:

abc|r=1,f=2,c=2|1
abc|r=1,f=2,c=2;r=3,f=4,c=8|1
abc|r=1,f=2,c=2;r=3,f=4,c=8|3

第三列值为 r 值。每次出现都会插入一个新行。

我尝试过:

for i in `cat $xxxx.txt`
    do
        #echo $i
        live=$(echo $i | awk -F " " '{print $1}')
        home=$(echo $i | awk -F " " '{print $2}')

        echo $live
    done

但工作不正常。我是sed/awk的初学者,不知道如何使用它们。有人可以帮忙吗?

3 个答案:

答案 0 :(得分:2)

awk救援!

$ awk -F'[,;|]' '{c=0; 
                  for(i=2;i<=NF;i++) 
                    if(match($i,/^r=/)) a[c++]=substr($i,RSTART+2);
                  delim=substr($0,length($0))=="|"?"":"|"; 
                  for(i=0;i<c;i++) print $0 delim a[i]}' file

abc|r=1,f=2,c=2|1
abc|r=1,f=2,c=2;r=3,f=4,c=8|1
abc|r=1,f=2,c=2;r=3,f=4,c=8|3

答案 1 :(得分:1)

使用内部例程(由 GNU grepsedtr组成)编译第二个更精细的sed命令,其输出需要进一步清理更多sed。调用输入文件“ foo ”。

sed -n $(grep -no 'r=[0-9]*' foo | \
         sed 's/^[0-9]*/&s#.*#\&/;s/:r=/|/;s/.*/&#p;/' | \
         tr -d '\n') foo | \
sed 's/|[0-9|]*|/|/'

输出:

abc|r=1,f=2,c=2|1
abc|r=1,f=2,c=2;r=3,f=4,c=8|1
abc|r=1,f=2,c=2;r=3,f=4,c=8|3

查看内部sed代码:

grep -no 'r=[0-9]*' foo | \
     sed 's/^[0-9]*/&s#.*#\&/;s/:r=/|/;s/.*/&#p;/' | \
     tr -d '\n'

它的目的是即时解析 foo (当 foo 更改时,输出也会更改),并在此实例中提出:

1s#.*#&|1#p;2s#.*#&|1#p;2s#.*#&|3#p;

这几乎是完美的,但它留在最后一行的旧数据中:

sed -n '1s#.*#&|1#p;2s#.*#&|1#p;2s#.*#&|3#p;' foo
abc|r=1,f=2,c=2|1
abc|r=1,f=2,c=2;r=3,f=4,c=8|1
abc|r=1,f=2,c=2;r=3,f=4,c=8|1|3

...旧数据|1是最终sed 's/|[0-9|]*|/|/'删除的内容。

答案 2 :(得分:1)

这是一个纯粹的bash解决方案。我不建议实际使用此功能,但它可能有助于您更好地了解如何使用bash中的文件。

# Iterate over each line, splitting into three fields
# using | as the delimiter. (f3 is only there to make
# sure a trailing | is not included in the value of f2)
while IFS="|" read -r f1 f2 f3; do

    # Create an array of variable groups from $f2, using ;
    # as the delimiter
    IFS=";" read -a groups <<< "$f2"
    for group in "${groups[@]}"; do

        # Get each variable from the group separately
        # by splitting on ,
        IFS=, read -a vars <<< "$group"

        for var in "${vars[@]}"; do
            # Split each assignment on =, create
            # the variable for real, and quit once we
            # have found r
            IFS== read name value <<< "$var"
            declare "$name=$value"
            [[ $name == r ]] && break
        done

        # Output the desired line for the current value of r
        printf '%s|%s|%s\n' "$f1" "$f2" "$r"
    done
done < $xxxx.txt

ksh的更改:

  1. read -A代替read -a
  2. typeset代替declare
  3. 如果<<<出现问题,您可以改用here here。例如:

    IFS=";" read -A groups <<EOF
    $f2
    EOF