如何打印输入中未包含的所有可能行?

时间:2016-04-29 07:06:48

标签: bash shell unix awk command-line

我有一个文本文件,其中每一行看起来像这样:

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),我应该选择哪种方式来解决这个问题?

4 个答案:

答案 0 :(得分:2)

如果您使用完整的数字集生成文件

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

答案 1 :(得分:1)

您应生成包含所有可能输入的文件,然后提供以下命令:

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

答案 2 :(得分:1)

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将从输出中省略条目。

答案 3 :(得分:1)

或者如果你喜欢慢蛮力方法,你可以在bash中使用循环(这对大数范围不好 - 超过~10的任何东西最好在awk或使用{{1}完成}解决方案)。但是,由于全字匹配,这确实提供了正确的数字排序顺序:

grep -f

输入文件

#!/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一起使用)