我正在尝试在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
从文件中读取要处理的文件名列表,单个-
代表标准输入。 (-T
AKA--files-from=
选项存在于 GNU tar 中,我不确定其他风格。)当然,如果您设法处理\n
名称中包含的文件,这会中断。
答案2
您无法可靠地对 find 的输出进行后处理。用于:-exec
find
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 之前的所有尝试中,我期望写入的所有输出文件都被覆盖,我的问题是之后它们是空文件。