【问题标题】:Using find and cat to duplicate the content of multiple files使用 find 和 cat 复制多个文件的内容
【发布时间】:2020-12-03 11:49:42
【问题描述】:

亲爱的,

我尝试在 bash 脚本中结合使用“find”和“cat”来复制子目录中数百个文件的内容:

find ./inlet3/* -type f -name 'U' -exec bash -c 'cat "{}"' \; > temp -exec bash -c 'cat temp >> "{}"' \;

查看给定的命令,我打算首先将每个“U”的内容复制到一个名为“temp”的临时文件中,该文件应该每次都在bash脚本所在的目录中创建。这部分应该通过以下方法实现:

-exec bash -c 'cat "{}"' \; > temp

“temp”的内容随后应附加到“U”,以获得具有重复内容的文件。这部分应该通过给定的方法来完成:

-exec bash -c 'cat temp >> "{}"' \;

但是,该命令没有给我想要的结果。我预计对于通过 find 找到的每个“U”,“temp”都会被覆盖。但是我看到之前找到的“U”的内容被附加到“temp”中,积累了它的内容。如果我尝试使用以下方法删除“temp”:

-exec rm -rf temp \;

然后我会收到一个错误:

cat: temp: 没有这样的文件或目录

为了简单起见,我省略了其他一些 -exec 选项。

谁能说出我可能错在哪里?我很感激任何提示。

亲切的问候。

【问题讨论】:

  • 您希望 -execdir 而不是 -exec 在与 U 相同的目录中创建临时文件。
  • 不带引号的> temp 不会只是将所有输出从find 发送到temp,无论您在哪里运行它?可能缓冲?我想也许你的意思是在"cat {}"

标签: bash duplicates find cat


【解决方案1】:

您希望-execdir 而不是-exec 在与U 相同的目录中创建临时文件。并且重定向应该在bash 会话中:实际上所有shell 操作都可以在同一个shell 中运行:

find ... -execdir sh -c 'temp=$(mktemp) && cat "{}" > "$temp" && cat "$temp" >> "{}" && rm "$temp"'

如果你安装了moreutils包,你可以使用sponge而不需要创建临时文件:

find ... -execdir sh -c '{ cat "{}"; cat "{}"; } | sponge "{}"'

【讨论】:

  • 谢谢格伦,我采纳了你的第一个建议,它奏效了!我现在面临另一个问题,“sed:无法打开临时文件 ./inlet3/9.946/sedU0yVQf:打开的文件太多”。我知道这应该与: -exec sed -i '1,3d' {} \;或 -exec sed -i '$ d' {} \;我都在同一个命令中使用了 find。这是泄漏问题吗?
【解决方案2】:

传统上,我们说

echo foo > bar

echofoo 视为它的参数,并将其发送到标准输出,我们已将其重定向到 bar... 但不必这样写。事实上,echo 甚至不知道它的输出已被重定向。那是处理流的解析器,所以结果意味着你可以用一些奇怪的方式编写命令 -

echo > bar foo 

同样有效

> bar echo foo

这是违反直觉的,但确实如此。

你的命令是

find ./inlet3/* -type f -name 'U' -exec bash -c 'cat "{}"' \; > temp -exec bash -c 'cat temp >> "{}"' \;

这在功能上与

相同
find ./inlet3/* -type f -name 'U' -exec bash -c 'cat "{}"' \; -exec bash -c 'cat temp >> "{}"' \;  > temp

> temp find ./inlet3/* -type f -name 'U' -exec bash -c 'cat "{}"' \; -exec bash -c 'cat temp >> "{}"' \;

因此,find 的所有输出都将进入temp

你想要的是

find ./inlet3/* -type f -name 'U' -exec bash -c 'cat "{} >| temp"' \; -exec bash -c 'cat temp >> "{}"' \;

除非你 set -o noclobber > 的结果在功能上与 >| 相同,但是当我想要截断时我倾向于明确。它永远不会痛。

正如 Glenn Jackman 指出的那样,更少的子shell 也更好,所以 -

find ./inlet3/* -type f -name 'U' -exec bash -c 'cat "{}" >| temp && cat temp >> "{}"' \;

【讨论】:

  • 为了比较,Glenn 的出色答案将让find 在找到名为U 的文件的每个目录中创建并清理一个不同的temp。我上面的答案将在记录的目录中创建一个文件并每次都对其进行 tuncate/overwrite,之后我没有清理它。两者都是学习的巧妙技巧。他也是对的,最好每次命中都在一个子shell中完成 - 我会偷那个花絮。 ;)
猜你喜欢
  • 2017-09-08
  • 2021-03-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-02
相关资源
最近更新 更多