linux - AWK 如何修改此代码以打印 num 个实例而不是 0 和 1

标签 linux awk

我有一个 bash 脚本,其中包含一些 AWK,用于解决我要解决的问题。

<targets.txt xargs -n1 -P4 bash -c "
awk 'NR==FNR{a[\$0];next} 
{
  if (\$0 in a) 
  {
    printf \"1,\"
  } 
  else 
  {
    printf \"0,\"
  }
}' \"\$1\" values.txt | sed $'s\x01$\x01'\"\$(<<<\"\$1\" cut -d/ -f3)\"'\n'$'\x01'

如果 a 中出现 $0,则打印“1,”,否则打印“0,”。但是,如果出现了,我不想打印 1,而是打印出现的次数。

有办法吗?

示例 targets.txt

./dataset/tallperson/file1.txt
./dataset/tallperson/file2.txt
./dataset/tallperson/file3.txt
./dataset/shortperson/file4.txt

例子./dataset/tallperson/file1.txt

LOL
Lol
Hel
lo.

例子./dataset/tallperson/file2.txt

LOL
LOL
Wei
rd.

例子./dataset/tallperson/file3.txt

Lol
Lol

例子./dataset/shortperson/file4.txt

hah
a t
hat
was
fun
ny.
LOL
LOL

示例值.txt

LOL
Lol
Hel
lo.
Wei
rd.
hah
a t
hat
was
fun
ny.

期望的输出

1,1,1,1,0,0,0,0,0,0,0,0,tallperson
2,0,0,0,1,1,0,0,0,0,0,0,tallperson
0,2,0,0,0,0,0,0,0,0,0,0,tallperson
2,0,0,0,0,0,1,1,1,1,1,1,shortperson

不需要的输出(来 self 的脚本)

1,1,1,1,0,0,0,0,0,0,0,0,tallperson
1,0,0,0,1,1,0,0,0,0,0,0,tallperson
0,1,0,0,0,0,0,0,0,0,0,0,tallperson
1,0,0,0,0,0,1,1,1,1,1,1,shortperson

我有 values.txt,其中包含 targets.txt 中每个文件的唯一 3 字符值列表。没有 file.txt 包含不在 targets.txt 中的值。我只想查看 targets.txt 中的每个文件,并计算该文件包含 values.txt 中的每个值的数量。

最佳答案

除了 awk 之外你不需要任何东西来做这件事,例如使用 GNU awk 进行 gensub()、ARGIND 和 ENDFILE:

$ cat tst.awk
BEGIN { OFS="," }
ARGIND == 1 {
    ARGV[ARGC] = $0
    ARGC++
    next
}
ARGIND == 2 {
    strings[++numStrings] = $0
    next
}
{ cnt[$0]++ }
ENDFILE {
    if ( ARGIND > 2 ) {
        for (stringNr=1; stringNr<=numStrings; stringNr++) {
            string = strings[stringNr]
            printf "%d%s", cnt[string], OFS
        }
        print gensub(/(.*\/)?([^/]+)\/[^/]+$/,"\\2",1,FILENAME)
        delete cnt
    }
}
$ awk -f tst.awk targets.txt values.txt
1,1,1,1,0,0,0,0,0,0,0,0,tallperson
2,0,0,0,1,1,0,0,0,0,0,0,tallperson
0,2,0,0,0,0,0,0,0,0,0,0,tallperson
2,0,0,0,0,0,1,1,1,1,1,1,shortperson

当然,您实际上并不需要“values.txt”文件,除非您确实需要无法根据输入确定的输出字段的特定顺序:

$ cat tst.awk
BEGIN { OFS="," }
ARGIND == 1 {
    ARGV[ARGC] = $0
    ARGC++
    next
}
{
    if ( !seen[$0]++ ) {
        strings[++numStrings] = $0
    }
    cnt[ARGIND,$0]++
}
END {
    for (stringNr=1; stringNr<=numStrings; stringNr++) {
        string = strings[stringNr]
        printf "%s%s", string, OFS
    }
    print "directory"

    for (fileNr=2; fileNr<=ARGIND; fileNr++) {
        for (stringNr=1; stringNr<=numStrings; stringNr++) {
            string = strings[stringNr]
            printf "%d%s", cnt[fileNr,string], OFS
        }
        print gensub(/(.*\/)?([^/]+)\/[^/]+$/,"\\2",1,ARGV[fileNr])
    }
}

$ awk -f tst.awk targets.txt
LOL,Lol,Hel,lo.,Wei,rd.,hah,a t,hat,was,fun,ny.,directory
1,1,1,1,0,0,0,0,0,0,0,0,tallperson
2,0,0,0,1,1,0,0,0,0,0,0,tallperson
0,2,0,0,0,0,0,0,0,0,0,0,tallperson
2,0,0,0,0,0,1,1,1,1,1,1,shortperson

我在第二个脚本中添加了一个 header - 如果您不想要它,请不要添加它。

如果您真的不关心输出顺序,那么您只需要:

$ cat tst.awk
BEGIN { OFS="," }
ARGIND == 1 {
    ARGV[ARGC] = $0
    ARGC++
    next
}
{
    strings[$0]
    cnt[ARGIND,$0]++
}
END {
    for (string in strings) {
        printf "%s%s", string, OFS
    }
    print "directory"

    for (fileNr=2; fileNr<=ARGIND; fileNr++) {
        for (string in strings) {
            printf "%d%s", cnt[fileNr,string], OFS
        }
        print gensub(/(.*\/)?([^/]+)\/[^/]+$/,"\\2",1,ARGV[fileNr])
    }
}

$ awk -f tst.awk targets.txt
was,rd.,Lol,ny.,LOL,Wei,hat,hah,lo.,fun,a t,Hel,directory
0,0,1,0,1,0,0,0,1,0,0,1,tallperson
0,1,0,0,2,1,0,0,0,0,0,0,tallperson
0,0,2,0,0,0,0,0,0,0,0,0,tallperson
1,0,0,1,2,0,1,1,0,1,1,0,shortperson

关于linux - AWK 如何修改此代码以打印 num 个实例而不是 0 和 1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57000583/

相关文章:

linux - 使用make命令安装touch Egg时

bash - 如何使用 awk 检测只有一个字段的行并将其与下一行一起打印?

linux - 如何在系统命令中使用 awk 脚本的 shell 变量?

python - 边列表中唯一的节点列表

linux - 如何合并唯一值和重复列

networking - 使用 AWK 计算 NS2 中的吞吐量

python - 如何从 python 中调用安装在 linux 上的程序?

Linux命令了解系统配置

linux - 如何使用定时任务

c++ - 数据包在 libnetfilter_queue 中永远循环