如何在没有 xargs 的情况下对从 stdin 获取的文件进行分类

如何在没有 xargs 的情况下对从 stdin 获取的文件进行分类

为了更好地学习 shell,并且不必总是求助于 xargs,我一直在尝试发现任何其他方法:

find . -name *.tcl | xargs -I{} cat {}

xargs 让它感觉很混乱,我想知道是否有多种方法可以实现这一点。

编辑:我确实发现另一种解决方案是使用:

find . -name "*.tcl" | cat `cat /dev/stdin`

我不明白为什么我必须先 cat 一个文件名,然后 cat 将其视为文件而不是字符串......

答案1

您还可以在子进程中使用 find 并将输出提供给 cat :)

cat $(find . -name "*.tcl")

答案2

您可以在查找中使用 exec:

find . -name "*.tcl" -exec cat {} \;

-exec和 尾随之间的所有内容\;都是要运行的命令。与 xargs 一样,您可以将查找结果替换为 {}。对于找到的每个文件,都会运行 cat (很像 xargs 如何迭代通过 STDIN 给出的文件列表)。

有些人可能会认为这更有效,因为您没有使用管道或启动另一个应用程序。

答案3

如果您使用bash,只需:

shopt -s globstar # to match files recursively
cat -- **/*.tcl

答案4

为了简单起见,我更喜欢这个已经提出的干净且可读的解决方案马克·科马林斯基。然而,在 Bash 中有很多方法可以做到这一点。另一种有趣的方法是完全避免cat并利用重定向:

find . -name '*.tcl' -exec sh -c 'printf "%s\n" "$(< {})' \;;

事实上,如果您想纯粹使用 Bash 内置函数来完成整个任务,那么您可以将重定向与混沌带来的全局解:

shopt_globstar_temp="$(shopt -p globstar)";
shopt -s globstar;
for filename in **/*.bat; do
    printf "%s" "$(< "${filename}")";
done;
${shopt_globstar_temp};

这些有点令人费解,但我在这里的目的是为了说明 Bash 可以做到文件描述符和重定向的一些强大功能。给定问题通常有多种解决方案。


我不明白为什么我必须先 cat 一个文件名,然后 cat 将其视为文件而不是字符串......

的输出cat /dev/fd/stdin将与上一个示例中的输出相同find,因此它将有效地被该文件列表替换<filename1>.tcl <filename2>.tcl ...cat使用该文件列表作为其参数列表。

如果您想知道为什么必须stdin在同一示例中使用 cat,原因是并非所有程序都stdin以与处理参数相同的方式处理。如果数据传输到catthrough stdin,则将cat简单地输出相同的数据,而不是将其解释为要读取的文件名。

相关内容