2014-10-10 22 views
0

我寫一個shell腳本來模擬多線程是這樣的:多線程殼for循環與找到包含文件名的空格

#!/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 

這是確定的,但它不會等待後臺進程完成日常:

= start = 
... 
... 
= end = 
2f6add89a29b1315166255c41899744b ./my img.jpg 
... 

我應該如何解決這個問題?

+0

BashPitfalls#1:http://mywiki.wooledge.org/BashPitfalls – 2014-10-10 17:44:44

+0

... waitaminute。你已經用空格解決了這個問題,那麼你爲什麼仍然是你題目的一部分,還有一半是你的問題?感覺就像我浪費了很多時間閱讀你已經修好的東西。 – 2014-10-10 17:45:36

+0

請注意MVCE的「最小」部分:http://stackoverflow.com/help/mcve – 2014-10-10 17:46:07

回答

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

如果你確信使用for循環而不是while循環的其他問題可以是固定的,這是直接了當:使用while循環讀取從find NUL分隔的結果轉換成一個數組,然後遍歷數組的內容爲for循環。

contents=() 
while IFS='' read -r -d '' filename; do 
    contents+=("$filename") 
done < <(find "$1" -iname '*.jpg' -print0) 

for filename in "${contents[@]}"; do 
    ... 
done