我编写了一个shell脚本来模拟多线程,如下所示:
#!/bin/sh
PROCESS_NUM=5
FIFO=/tmp/$$.fifo
mkfifo $FIFO
exec 3<>$FIFO
for i in $(seq 1 $PROCESS_NUM); do
echo $i>&3
done
echo "= start ="
for i in $(find "$1" -iname "*.jpg")
do
read -u3 p
{
md5sum "$i"
echo $p>&3
} &
done
wait
exec 3>&-
rm $FIFO
echo "= end ="
没关系,输出如下:
= start =
2f6add89a29b1315166255c41899744b ./img.jpg
...
...
...
= end =
但是当文件路径包含空格时,它就是错误并输出如下:
= start =
md5sum: ./my: No such file or directory
md5sum: img.jpg: No such file or directory
...
...
...
= end =
所以我改变了这样的循环:
find "$1" -iname "*.jpg"|while read i
do
read -u3 p
{
md5sum "$i"
echo $p>&3
} &
done
没关系,但它不会等待后台进程finsh:
= start =
...
...
= end =
2f6add89a29b1315166255c41899744b ./my img.jpg
...
我该如何解决这个问题?
答案 0 :(得分:2)
作业控制并非用于非交互式使用 - 就此而言,作业表的大小非常有限,并且在内容溢出时会丢弃内容。
收集PID,并单独等待它们。
pids=( )
while IFS='' read -r -d '' filename; do
{ your_stuff_here; } &
pids+=( "$?" )
done < <(find "$1" -iname '*.jpg' -print0)
for pid in "${pids[@]}"; do wait "$pid"; done
请注意IFS='' read -r -d ''
和find -print0
的使用 - 否则,您会遇到包含反斜杠转义序列或换行符的文件名的糟糕日子(两者都是,对于POSIX完全有效)文件系统)。
答案 1 :(得分:1)
如果您确信使用for
循环而不是while
循环可以解决其他问题,则可以直接完成:使用while
循环来读取NUL分隔从find
到数组的结果,然后使用for
循环迭代数组的内容。
contents=( )
while IFS='' read -r -d '' filename; do
contents+=( "$filename" )
done < <(find "$1" -iname '*.jpg' -print0)
for filename in "${contents[@]}"; do
...
done