我有一个很大的文件元组列表,格式如下:
A_1.txt
A_2.txt
B_1.txt
B_2.txt
C_1.txt <<
D_1.txt
D_2.txt
E_1.txt
E_2.txt
在一个目录中。正如你所看到的,C_2.txt
我的列表中缺少它。我需要找到一种巧妙的方法来查找其中哪些文件缺少其“伙伴”,并使用bash
.我想我需要修改这个:
x=$(pwd)
find $x -type f -printf '%f\n' | sort | uniq -c
包含 {0:1},这样它只搜索列表的前 1 个字符,并打印有多少个文件以该第一个字符开头。
预期输出:
2 A
2 B
1 C
2 D
2 E
或(理想)预期输出:
C_1.txt
答案1
循环文件名,提取前缀(第一个之前的字符串_
)并检查有多少文件以该前缀开头(我使用过set
,但您也可以使用数组并检查其长度)。
如果只有一个,则打印它的名称:
for f in ./*.txt; do
n=${f%%_*}
set -- "${n}"_*
[ $# -eq 1 ] && printf '%s\n' "${f}"
done
set --
答案2
通过管道将您的文件列表传输到
sed -n '$!N;/\(.*\)1.txt\n\12.txt/!{P;D;}'
这总是读取一对行,如果它不是一对,则something1.txt
打印something2.txt
孤行,因此它给出了“理想的预期输出”。
详细解释:
N
将下一行追加到模式空间,因此您有两行,包括中间的换行符/\(.*\)1.txt\n\12.txt/
是一个“地址”,选择是否执行下一条命令。这可以是行号、范围,或者在本例中是必须与模式空间匹配的正则表达式。.*
可以匹配任何字符串,并且通过用 包围它,\(.*\)
我们可以稍后将其反向引用为\1
。 So\n\12
表示换行符,后跟从头开始的字符串,最后是2
.因此,我们正在寻找anystring1.txt
anystring2.txt
- 地址后的内容
!
会反转匹配,因此仅当模式空间与表达式不匹配时才会执行以下操作。如果线路不属于一对,就会出现这种情况。 - 形成
{}
命令块,这意味着仅当模式匹配时才会执行其中的所有命令 P
将模式空间打印到第一个换行符,因此仅打印第一行(因为我们不知道第二行是否属于一对)。- 最后
D
删除第一个换行符之前的模式空间,并从剩余的行开始下一个循环,该行将再次尝试与下一行配对。
我希望这个解释可以帮助您了解一些sed
。 *