我有一个以下形式的文本文件:
dir1/sub-dir1/.../filename1 author date
dir1/sub-dir1/.../filename2 author date
.
.
.
dir2/sub-di2/.../filename1 author date
dir2/sub-dir2/.../filename2 author date
额外细节:
- 列出的每个文件名恰好存在 1 次或 2 次。也就是说,
filename_n
恰好存在 1 次或 2 次。如果它存在 1 次,则它仅存在于我们软件的 1 个版本中,即 v1 或 v2,具体取决于路径。如果存在2次,则该文件同时是v1和v2。 - 该路径确定文件是 v1 还是 v2。
- 文本文件以制表符分隔。
- 子目录的数量因文件而异(因此
...
在代码块中)。 - (作者和日期不是从 中获取的
ls
。它们是通过询问最后记录对这些文件的更改的 git 提交而单独生成的。)
我尝试使用 sed 和正则表达式来转换文件,使其看起来像这样:
dir1/sub-dir1/.../filename1 author date dir2/sub-di2/.../filename1 author date
dir1/sub-dir1/.../filename2 author date dir2/sub-dir2/.../filename2 author date
.
.
.
如果filename-n
没有匹配项,则它应该只出现一次,而不是两次。
我正在寻找一种使用 sed 和正则表达式来执行转换的方法。它可以写入同一个文件(使用-i
),也可以写入单独的文件。
答案1
可以完全使用 来完成此操作sed
,但这会导致难以理解的复杂脚本,因此我建议先按文件名对文件进行排序,然后sed
在发现文件名两次时使用 来连接行。
文件名位于第三个子目录中,我们告诉我们sort
使用第四个字段 ( -k 4
) 和\
(到底为什么!!)作为字段分隔符:
sort -t'\' -k 4 /tmp/p|sed 'N;/\(\\[^\]* \).*\1/s/\n/ /;P;D'
该sed
命令使用典型的N;P;D
循环来始终一次处理两行并检查文件名(在\
TAB 之间)是否重复。
请注意,脚本中有两个文字选项卡sed
。使用 GNU sed
,你可以\t
这样写:
sort -t'\' -k 4 /tmp/p|sed 'N;/\(\\[^\]*\t\).*\1/s/\n/\t/;P;D'
另请注意,包含制表符或反斜杠的路径可能会破坏脚本。
答案2
在每个 Unix 机器上的任何 shell 中使用任何 awk,无论您的路径包含哪些字符(换行符除外):
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{
file = $0
sub(".*/","",file)
paths[file] = (file in paths ? paths[file] OFS : "") $0
}
END {
for ( file in paths ) {
print paths[file]
}
}
$ awk -f tst.awk file
dir1/sub-dir1/.../filename2 author date dir2/sub-dir2/.../filename2 author date
. . .
dir1/sub-dir1/.../filename1 author date dir2/sub-di2/.../filename1 author date
如果输出顺序确实很重要,那么这是一个微不足道的调整 - 只需告诉我们输出顺序应该是什么(例如首先读取,按文件名字母顺序,按目录字母顺序,其他)。