使用 find 的 exec 功能

使用 find 的 exec 功能

我正在尝试在for循环中执行以下操作:

  • 查找满足条件的文件
  • 将文件名回显到日志文件。
  • 对文件进行压缩。

我可以让脚本查找文件并将其名称回显到屏幕,但无法将它们通过管道传输到文件。 (我还没有测试 gzip 部分)

这是脚本的相关部分(存在$LOGCLEAN_FILE并写入脚本的早期部分):

for F in `find . -type f \( ! -name '*.gz' \) -a \( ! -name '*.Z' \) -mtime +7`
do

        {
        print "Will be compressing file  ${F}" >> $LOGCLEAN_FILE
        } ; 
        ##gzip $F
done

如果我运行没有文本的脚本" >> $LOGCLEAN_FILE",则输出将显示在屏幕上。

我究竟做错了什么?

欢迎批评——我仍在学习。

答案1

实际上没有必要find在 shell 循环中重现 的输出。如果你想打包文件名列表,通用公式为:

find ... | gzip > logfile.gz

如果你想压缩文件本身,则变为:

find ... | tar -czvf archive.tar.gz -T -

它告诉tar从文件中读取要处理的文件名列表,单个-代表标准输入。 (-TAKA--files-from=选项存在于 GNU tar 中,我不确定其他风格。)当然,如果您设法处理\n名称中包含的文件,这会中断。

答案2

您无法可靠地对 find 的输出进行后处理。用于:-execfind

find . -type f ! -name '*.gz' ! -name '*.Z' -mtime +7 -exec sh -c '
  for i do
    printf "%s\n" "Will be compressing file $i"
    gzip "$i"
  done' sh {} + >> log

通过 GNU 实现find,您甚至可以在不运行 sh 的情况下逃脱:

find . -type f ! -name '*.gz' ! -name '*.Z' -mtime +7 \
  -printf 'Will be compressing file %p\n' -exec gzip {} + >> log

答案3

将重定向 ( >>) 放在循环之外( after done),如下所示:

for i in $(find . -type f \( ! -name '*.gz' \) -a \( ! -name '*.Z' \) -mtime +7);
  do echo "Will be compressing file  ${i}";
  ##gzip $i;
done >> $LOGCLEAN_FILE

或者,如果您计划最终取消注释您的gzip命令,您可能会考虑:

for i in $(find . -type f \( ! -name '*.gz' \) -a \( ! -name '*.Z' \) -mtime +7);
  do gzip "$i" && echo "Successfully compressed ${i}";
done >> $LOGCLEAN_FILE

如果上一个命令退出(无错误),则意味着&&仅执行下一个命令。0

答案4

如果您尝试通过管道传输到输出文件,迭代文件路径...

使用 find 的 exec 功能

...处理您的迭代。

我想通过子 shell 迭代显式文件列表,并将expand其输出调用到 stdout,并覆盖每个单独的文件。此答案解决的问题

find $(git ls-files | grep '.py$') \
    -exec bash -c 'expand -t 4 "$0" > /tmp/e && mv /tmp/e "$0"' {} \;

我正在重新发布该答案的稍微修改版本,因为该线程中的其他答案没有提供通用解决方案。这是我见过的唯一有效的方法,它仅适用于迭代文件路径时。

我可以想象一个解决方案,它滥用地创建以迭代项命名的文件,以便您可以使用 find 迭代该名称。


失败的尝试:

就像 find exec 调用一样,我尝试bash -c ...在 for 循环内部使用。但我遇到了同样的空输出文件问题。

免责声明:我不确定我的问题到底是什么,在使用 find exec 之前的所有尝试中,我期望写入的所有输出文件都被覆盖,我的问题是之后它们是空文件。

相关内容