Shell 脚本 while read 循环仅执行一次
我正在编写一个 shell 脚本,通过 Handbrake 批处理相机上的 .mov 文件以保存高清空间。该脚本使用“find”搜索目录,然后对找到的每个 .mov 文件运行 Handbrake,使用“touch”将结果文件的创建日期与源文件的日期进行匹配。
我最初使用 for 循环执行此操作:
for i in $(find "$*" -iname '*.mov') ; do
~/Unix/HandbrakeCLI --input "$i" --output "$i".mp4 --preset="Normal"
touch -r "$i" "$i".mp4
done
这有效,但如果输入文件的文件名中包含空格,则会失败。所以我尝试了一个 while 循环:
find "$*" -iname '*.mov' | while read i ; do
~/Unix/HandbrakeCLI --input "$i" --output "$i".mp4 --preset="Normal"
touch -r "$i" "$i".mp4
done
这个循环的问题是它适用于目录中的第一个文件,然后退出循环。请注意,如果我在 while 循环体中替换“echo $i”,它将打印目录中的所有 .mov 文件,因此循环结构正确。
我相信我的问题有部分答案 这个 stackoverflow 线程。但该解决方案是针对 ssh 的,并不能解决一般问题。似乎与子进程使用 stdin 有关,但我不太明白这是如何工作的。
有什么建议吗?
我使用的是 OSX 10.6
I am writing a shell script to batch process .mov files off my camera through Handbrake to save HD space. The script searches a directory with 'find' and then runs Handbrake on each .mov file found, matching the creation date of the resulting file to the source file's date with 'touch'.
I originally did this with a for loop:
for i in $(find "$*" -iname '*.mov') ; do
~/Unix/HandbrakeCLI --input "$i" --output "$i".mp4 --preset="Normal"
touch -r "$i" "$i".mp4
done
This worked, but failed if the input files had spaces in their file names. So I tried a while loop instead:
find "$*" -iname '*.mov' | while read i ; do
~/Unix/HandbrakeCLI --input "$i" --output "$i".mp4 --preset="Normal"
touch -r "$i" "$i".mp4
done
The problem with this loop is that it works for the first file in the directory, and then exits the loop. Note that if I substitute an "echo $i" in the body of the while loop, it prints all of the .mov files in the directory, so the loop is structured correctly.
I believe there is a partial answer to my question on this stackoverflow thread. But the solution is specific to ssh and doesn't solve the general problem. Seems to have something do do with stdin being used by a sub-process, but I don't exactly understand how this works.
Any advice?
I'm on OSX 10.6
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
摘自这个答案:我现在不向 HandbrakeCLI 回显任何内容,以确保它没有使用与我的脚本相同的标准输入:
...它按预期/预期工作。
Taken from this answer: I now echo nothing into HandbrakeCLI to ensure it's not using the same stdin as my script:
...and it works as intended/expected.
一种可能性是使用安全查找:
这应该与 POSIX 兼容,但仅当
HandbrakeCLI
和touch
均未从标准输入读取且文件名不包含换行符时才有效:One possibility is to use the safe find:
This should be POSIX compatible, but only works if neither
HandbrakeCLI
nortouch
read from standard input and no file names contain newlines:您可能正在使用 shellopt '-e'(错误时退出)运行
尝试
You are probably running with a shellopt '-e' (exit on errors)
Try
此链接解决了我在 Ubuntu Linux 11.04 上的问题。
防止子进程 (HandbrakeCLI)导致父脚本退出
这是适合我的代码:
This link fixed the problem for me on Ubuntu Linux 11.04 .
Preventing a child process (HandbrakeCLI) from causing the parent script to exit
Here is the code that works for me:
我也有同样的问题。我认为 HandbrakeCLI 正在消耗标准输入。我这里没有实际的系统,但我的测试表明这可能会发生。
“output”是一个包含数字 1-10 的文件,每个数字各占一行。
Consumer.sh:
结果:
更改外部 while 循环将解决问题:
结果:
I've got the same problem. I think HandbrakeCLI is consuming stdin. I don't have my actual system here, but my testing shows that's what is probably happening.
"output" is a file with the numbers 1-10, each on their own line.
consumer.sh:
Results:
Changing the outer while loop will fix the problem:
Results:
考虑仅使用
find
来调用 shell,而不是将find
包装在while
循环中。Consider just using
find
to invoke a shell, instead of wrappingfind
in awhile
loop.