![tar 列出文件,在第一个文件处中断](https://linux22.com/image/106077/tar%20%E5%88%97%E5%87%BA%E6%96%87%E4%BB%B6%EF%BC%8C%E5%9C%A8%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%E5%A4%84%E4%B8%AD%E6%96%AD.png)
我一直在使用从类似帖子中提取的以下片段 -https://unix.stackexchange.com/a/101273/212793- 从文件中获取文件名tar.gz
:
tar tzf "archive.tar.gz" | awk -F/ '{ if($NF != "") print $NF }'
就我而言,我只需要一个特定文件,因此我使用类似以下内容的文件:
tar tzf "archive.tar.gz" | awk -F/ '{ if($NF != "") print $NF }' | grep -e "^..*my-file-name\\.ext$"
关键是,我的.tar.gz
很大,包含很多文件。然而,每个都在开头附加了一个类似的“哈希”(因此是^..*
我的 grep'd 正则表达式的一部分)。
所以这些文件可能看起来像:
- 4b77e4e1_file-a.ext
- 4b77e4e1_file-b.ext
- 4b77e4e1_file-c.ext
# ect.
tar tzf "archive.tar.gz" | awk -F/ '{ if($NF != "") print $NF }'
我注意到获取所有文件 ( ) 流输出的命令。
我的想法是,如果我可以“破坏”流,然后提取第一个哈希部分,我就可以构建我最终需要的文件名,而不必循环遍历文件的整个内容.tar.gz
。
所以我的问题是,如何。awk
在其第一个输出上“中断”,而不是等待整个命令完成(这需要几分钟)并 grep 结果以获得我最终想要的文件名
编辑:看起来我实际上想中断tar
,因为exit
在第一个结果之后简单地 ing 不会改变执行时间。
答案1
尝试类似的东西
tar tzf "archive.tar.gz" | awk -F/ '$NF ~ /my-filename$/ {print $NF ; exit }'
或者
tar tzf "archive.tar.gz" | awk -F/ 'substr($NF,4,11) == "my-filename" {print $NF ; exit }'
(其中 4 和 11 与实际文件名匹配)。
答案2
如果管道中的程序之一退出,则其左侧的程序也将退出。它的工作方式是:
- 中
foo | bar
,bar
退出。 - 退出进程会关闭管道的读取端。
- 当
foo
尝试写入管道时,它会收到 SIGPIPE 信号。 foo
死了。
这是假设foo
没有针对 SIGPIPE 进行防护;程序可以做到这一点,但典型的命令行程序不能。
由于您只想要一场比赛,因此 awk 在找到您感兴趣的行后立即退出:
tar tzf "archive.tar.gz" | awk -F/ '$NF ~ /.my-file-name\.ext$/ {print $NF; exit}'
或者(这里并不是很有利)
tar tzf "archive.tar.gz" | sed -n '/[^/]my-file-name\.ext$/ {s!.*/!!; q}'
或者,坚持使用 grep 与 awk 分开的更复杂的方法
tar tzf "archive.tar.gz" | awk -F/ '{ if($NF != "") print $NF }' | grep -e "^..*my-file-name\\.ext$" | head -n 1
从读取器退出会导致tar
下次写入管道时退出,这可能需要一段时间,因为输出缓冲。 (如果管道上有两个以上的进程,则需要特别长的时间,因为每个进程接收 SIGPIPE 都会有一些延迟。)awk
退出后,find
将花费一点时间读取存档并用以下内容填充下一个缓冲区文件名,然后最后尝试写入缓冲区并被 SIGPIPE 杀死。对于此应用程序,将 tar 切换到行缓冲进行输出可能会更快,您可以使用stdbuf
:
stdbuf -oL tar tzf "archive.tar.gz" | awk -F/ '$NF ~ /.my-file-name\.ext$/ {print $NF; exit}'
或者,您可以安排在 awk 退出时终止 tar 程序,但这更复杂。
sh -m 'tar tzf "archive.tar.gz" | {
awk -F/ "$0";
kill -TERM -$$;
}' '$NF ~ /.my-file-name\.ext$/ {print $NF; exit}'
[ $? -eq 143 ]
答案3
您可以告诉 AWK 在打印某些内容后退出:
awk -F/ '$NF != "" { print $NF; exit }'
由于您正在寻找特定的文件名:
awk -F/ '/my-file-name\.ext$/ && $NF != "" { print $NF; exit }'
那么测试$NF
是多余的:
awk -F/ '/my-file-name\.ext$/ { print $NF; exit }'