多线程shell for循环查找文件名包含空格

时间:2014-10-10 17:33:20

标签: multithreading shell

我编写了一个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
...

我该如何解决这个问题?

2 个答案:

答案 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