【问题标题】:How to print all possible lines that are not included in the input?如何打印输入中未包含的所有可能行?
【发布时间】:2016-08-24 05:24:42
【问题描述】:

我有一个文本文件,其中每一行如下所示:

a_1/b_1/c_1
a_2/b_2/c_2
a_3/b_3/c_3
...    

其中 a_n、b_n 和 c_n 可以是从 M 到 N 的任意数字。例如,M=1 和 N=10,我的输入文件包含以下数据:

1/2/3
1/4/2
1/4/10
1/5/2
2/2/1
2/3/4    

我想要的是打印输入中未包含的所有可能行:

1/1/1
1/1/2
1/1/3
...
1/1/10
1/2/1
1/2/2
1/2/4
...
1/2/10
1/3/1
...
1/3/10
1/4/1
1/4/3
...
1/4/9
1/5/1
1/5/3
...
1/10/9
1/10/10
2/1/1
...
2/1/10
2/2/1
...
2/3/3
2/3/5
...
10/10/9
10/10/10

我应该使用什么工具(如果可能,我更喜欢使用 AWK),我应该选择哪种方式来解决这个任务?

【问题讨论】:

  • 您想要a_b_c_ 还是只是在a_b_c_ 之后尚未找到的数字(这就是您所显示的,但目前尚不清楚这是否只是简写)- 或者 a_b_c_ 只是用来显示有 3 数字?
  • @David:我不明白这个问题。 a_b_c_ 是什么意思?我用下划线表示mathematical subscripts,所以a_1 = a₁。在我的示例的第一行中,a₁=1, b₁ = 2, c₁=3。
  • 我想通了。您只是使用 abc 作为示例参考。不清楚你什么时候说"I have an input file..."a_1/b_1/c_1...
  • grep -vf test <(echo "$(printf "%s\n" {1..10}/{1..10}/{1..10})")

标签: bash shell unix awk command-line


【解决方案1】:

如果你生成一个包含完整数字集的文件

1/1/1
1/1/2
1/1/3
...
1/1/10
1/2/1
1/2/2
1/2/3
1/2/4
...

在model.txt (f.e.)

你可以用一个命令来完成:

 grep -v -f model.txt input.txt >> output.txt

更新:

要创建 model.txt 文件,您可以这样做:

for i in {1..10}
do
        for j in {1..10}
        do
                for l in {1..10}
                do
                        echo $i/$j/$l >> model.txt
                done
        done
done

【讨论】:

  • 你将如何生成model.txt
【解决方案2】:

你应该生成一个包含所有可能输入的文件,然后给出以下命令:

`grep -v -f <allpossibleinput> < <yourinput>`

【讨论】:

  • 具有所有可能输入的文件用作具有模式的文件(-f 标志)。输入文件中的所有值都与之匹配。这只会打印您的所有输入,但是使用 -v 标志它会打印相反的内容:所有与所有可能输入中的行不匹配的条目。
【解决方案3】:
awk -v m=1 -v n=10 '{
    a[$1]
}
END{
    for ( i=m; i<=n;i++){
        for( j=m; j<=n;j++){
            for( k=m; k<=n;k++){
                p=i"/"j"/"k;
                if (!( p in a )){
                    print p
                }
            }
        }
    }
}' file

file 将包含要从输出中省略的条目。

【讨论】:

  • 这个我还没有测试过,但是有些东西我不明白...你为什么不指定字段分隔符?为什么是$1,而不是$0?您只在a 中输入了第一个字段?我需要一些时间来测试这个......
  • @lyricallywicked 应该是$0
  • 由于空格是字段分隔符 $0 和 $1 包含相同的内容。
  • 是的,它按我的预期工作!我接受这个答案,因为它使用 AWK 并处理最少数量的文件(只有 2 个,而不是 3 个,如基于grep 的解决方案)。
【解决方案4】:

或者,如果您喜欢缓慢的蛮力方法,您可以在 bash 中使用循环(这对于大数字范围并不好——在 awk 或使用 grep -f 解决方案中最好完成 ~10 的任何事情)。但是,由于全字匹配,这确实提供了正确的数字排序顺序:

#!/bin/bash

test -z "$1" -o -z "$2" -o -z "$3" && { ## validate 3 args
    printf "error: insufficient input, usage: %s M N\n" "${0//*\//}"
    exit 1
}

test "$1" -eq "$1" >/dev/null 1>&2 || { ## validate 1st is int
    printf "error: invalid input, %s is not an integer\n" "$1"
    exit 1
}

test "$2" -eq "$2" >/dev/null 1>&2 || { ## validate 2nd is int
    printf "error: invalid input, %s is not an integer\n" "$2"
    exit 1
}

test -r "$3" || { ## validate 3rd is input file
    printf "error: invalid input, file '%s' not readable\n" "$3"
    exit 1
}

## for all i/j/k not found in input, output i/j/k
for ((i = $1; i <= $2; i++)); do
    for ((j = $1; j <= $2; j++)); do
        for ((k = $1; k <= $2; k++)); do
            grep -qw "$i/$j/$k" "$3" &>/dev/null || echo "$i/$j/$k"
        done
    done
done

输入文件

$ cat dat/3num.txt
1/2/3
1/4/2
1/4/10
1/5/2
2/2/1
2/3/4

示例输出

$ bash missing3.sh 1 10 dat/3num.txt
...
1/2/1
1/2/2
1/2/4
...
1/3/10
1/4/1
1/4/3
1/4/4
1/4/5
1/4/6
1/4/7
1/4/8
1/4/9
1/5/1
1/5/3
...

您将需要使用另一种不将grep 嵌入嵌套循环的解决方案,因为它很慢,但对于小范围来说还不错。

(稍作修改,您可以使用它来生成“所有可能的输入”文件以用于grep -f

【讨论】:

    猜你喜欢
    • 2022-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 2020-02-27
    • 2018-06-11
    相关资源
    最近更新 更多