【问题标题】:How can I get xargs to do something with the input, then do another thing?我怎样才能让 xargs 对输入做某事,然后再做另一件事?
【发布时间】:2015-09-05 22:00:49
【问题描述】:

我在 zsh 中。

我想做这样的事情:

find . -iname *.md | xargs cat && echo "---" > all_slides_with_separators_in_between.md

当然,这会涵盖所有幻灯片,然后在末尾而不是在每张幻灯片之后附加一个“---”。

有这样做的 xargs 方式吗?我可以用一些内联函数或do 块替换cat && echo "---" 吗?


很奇怪,当我用内容创建一个文件cat---.sh
cat $1
echo ---

然后运行

find . -iname *.md | xargs ./cat---.sh

它只对 find 的第一个结果执行。
用 cat 替换 cat---.sh 并在两个文件上运行。

【问题讨论】:

  • 我很确定这个问题是重复的。我会看看我是否能找到一个合适的老问题;然后应该关闭这个。
  • 顺便说一句,请参阅mywiki.wooledge.org/UsingFind 的“复杂操作”部分
  • 顺便说一句,尽管 zsh often 让你懒得引用,但调用 find 并不是其中之一。您需要-iname '*.md',而不是-iname *.md,否则在调用find 之前,glob 将被扩展以引用当前目录中的文件名(如果存在任何匹配项)。
  • 是的。如果脚本写成for arg; do cat "$arg" && echo ---; done,那就可以了。
  • @Freiheit,您是否承认shellbashzsh 等。标签在 StackOverflow 上有什么位置?如果他们这样做,是什么区分属于这里的问题和属于 unix.SE 的问题?

标签: shell command-line zsh xargs


【解决方案1】:

这里根本不需要使用xargs。以下是一种适当偏执的方法(对带有空格的文件、带有换行符的文件、名称中带有文字反斜杠的文件等具有鲁棒性):

while IFS= read -r -d '' filename; do
  printf '---\n'
  cat -- "$filename"
done < <(find . -iname '*.md' -print0) >all_slides_with_separators.md

但是——你甚至不需要它:find 可以自己完成所有工作,打印分隔符调用cat

find . -iname '*.md' -printf '---\n' -exec cat -- '{}' ';' >all_slides_with_separators.md

【讨论】:

  • 我的 find 版本(OSX 上的 BSD)没有 -printf,所以我需要 -exec echo '---' ';'。但否则它会起作用。谢谢。
【解决方案2】:

常见的使用模式是xargs sh -c 'command; another' _,其中引号中的整个 shell 脚本都可以访问命令行参数。下划线是因为sh -c 的第一个参数将分配给$0(您经常会在ps 列表中看到-sh)。

find . -iname '*.md' |
xargs sh -c 'for x; do
  cat "$x" && echo "---"
done' _ > all_slides_with_separators_in_between.md

正如 cmets 中所述,您可能应该调查find -print0 和 GNU find 中相应的 xargs -0 选项(如果没有,也可以安装它)。

【讨论】:

  • 需要在通配符周围加上引号,否则对于当前目录中的任何 .md 文件,这将严重失败。
  • 另外,可能值得建议使用 find -print0 / xargs -0 以避免文件或目录名称中的文字换行符带来令人不快的意外。
【解决方案3】:

您可以这样做,但在某些情况下可能不安全(参见 cmets):

find . -iname '*.md' | xargs -I % sh -c '{ cat %; echo "----"; }' &gt; output.txt

【讨论】:

  • 比任何一个预先存在的答案安全得多:这通过将作为脚本的一部分找到的文件传递给 sh 来评估文件名文字内的扩展。
  • 看看在mkdir -p '.evil/rm $(rm -rf ' &amp;&amp; touch '.evil/rm $(rm -rf /*).md' 之后运行它会发生什么。或者,如果您重视您的系统,请不要这样做。
  • 好吧,如果我将脚本更改为与@triplee 发布的相同,我们的答案将是相同的。这值得么?保持原样不是更好,以便其他人可以学习吗?如果我完全删除它,其他人可以想出与我相同的解决方案,但他不会了解它可能存在的问题。
  • 太棒了。谢谢你教会了我一些我不知道的东西!顺便说一句,我还将输出重定向移出脚本,所以它现在应该只打开一个文件,不是吗?
  • 很高兴能提供帮助 - 是的,将重定向移出解决了该问题。
【解决方案4】:

zsh 中很少需要find;它的 globbing 设施几乎涵盖了 find 的所有用例。

for f in (#i)**/*.md; do
    cat $f
    print -- "---"
done > all_slides.md

这会以不区分大小写的方式在当前目录层次结构中查找与 *.md 匹配的每个文件。

为了提高效率,请将cat $f 替换为&lt; $fzsh 本身会读取文件并将其内容写入标准输出。

【讨论】:

    【解决方案5】:

    使用 GNU Parallel 它看起来像这样:

    parallel cat {}\; print -- --- ::: **/*.md
    

    【讨论】:

      猜你喜欢
      • 2020-05-24
      • 2019-01-06
      • 2015-11-27
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2019-09-01
      • 1970-01-01
      相关资源
      最近更新 更多