在 Linux 中屏蔽文件中的位 - 按位运算

Joh*_*809 5 linux bash merge awk sed

我想在 Linux 中屏蔽文件中的位,如下所示:

 actual : 00-00000000-00000011-00110010-10000000
 expect : 00-00000000-00000001-01101010-00000000
 error  : 00-00000000-00000010-01011000-00000000
Run Code Online (Sandbox Code Playgroud)

在输出中,该actual部分应该保持原样,除非,error然后1actual应该被屏蔽X

可以看出,error是和数据的异或actualexpected

输出应该看起来像这样:

output : 00-00000000-000000X1-0X1XX010-10000000
Run Code Online (Sandbox Code Playgroud)

是否可以使用 SED、AWK 等命令来执行此操作?

到目前为止做了什么:

grep 'err' gpbat | sed 's?-??g' | cut -c 11-35 | sed 's?1?X?g' > a1
grep 'act' gpbat | sed 's?-??g' | cut -c 11- > a2
Run Code Online (Sandbox Code Playgroud)

但从这里开始,不知道如何合并a1&a2

jhn*_*hnc 4

对于许多版本的 awk:

awk '
    /actual/ { split($3,a,"") }
    /error/ { split($3,e,"") }

    END {
        for (i in a)
            c[i] = e[i]==1 ? "X" : a[i]

        for (i = length(c); i>0; --i)
            s = c[i] s

        printf "output : %s\n", s
    }
' gpbat
Run Code Online (Sandbox Code Playgroud)

POSIX 指出splitonempty string 的结果是未定义的行为“以允许提议的未来扩展将字符串拆分为单个字符数组”,但我个人还没有遇到过尚未这样做的版本。YMMV。为了实现完全的可移植性,@markp-fuso 的方法使用substr将是首选。


或者稍微更有效(根据@markp-fuso):

awk '
    /actual/ { n = split($3,a,"") }
    /error/ { split($3,e,"") }

    END {
        for (i = 1; i<=n; ++i)
            o = (o) ( e[i]==1 ? "X" : a[i] )
        print "output :", o
    }
' gpbat
Run Code Online (Sandbox Code Playgroud)

并且,如果保证输入的顺序,则可以在读取“错误”行后停止处理,因此操作可以与 an 一起END移动到操作中,以避免必须读取文件的其余部分:/error/exit

awk '
    /actual/ { n = split($3,a,"") }
    /error/ {
        split($3,e,"")
        for (i = 1; i<=n; ++i)
            o = (o) ( e[i]==1 ? "X" : a[i] )
        print "output :", o
        exit
    }
' gpbat
Run Code Online (Sandbox Code Playgroud)