2014-04-12 43 views
0

我寫的下一個測試shell腳本:

#!/bin/sh 
IFS=$'\n' 
for d in `find . -name *.cue -print0 | xargs -0 -n1 dirname | sort --unique` 
do 
    unset IFS 
    echo "$d" 
    IFS=$'\n' 
done 
unset IFS 

如果我在執行我獲得這樣的事情在bash的條件find命令:

./[FLAC] Destination Goa - The Sixth Chapter (CD)/CD2 
./[FLAC] Eat Static - Implant - (CD) 
./[FLAC] Elysium - Dance For The Celestial Beings (CD) 
./[FLAC] Elysium - Monzoon 1996 (CD) 
./[FLAC] Etnica - The Juggeling Alchemists Under The Black Light 

在shell腳本(含線索文件的文件夾的名稱),我想用這個文件夾中的每一個循環,但是,當然,如果我不重新定義IFS的occurreances打破空間:

Experience 
4 
./[FLAC] 
VA 
- 
Trancentral 
Five 
A 
Sonic 
Initiation 
./[FLAC] 
VA 
- 
Trancentral 

在其他計算機(MacOS的)我解決了這個問題改變了IFS到特徵線與此命令IFS=$'\n'但在我家的電腦(一個Ubuntu Linux)的環打破事件爲「N」:

tra 
ce - A Trip To Psychedelic Tra 
ce (CD)/CD1 
./[FLAC] VA - Ta 
tra 
ce - A Trip To Psychedelic Tra 
ce (CD)/CD2 
./[FLAC] VA - Tech 
o Tra 
ce Ma 

你知道發生了什麼,爲什麼計算機之間的不同行爲? 謝謝。

+1

什麼'/ bin/sh的--version'(或'/ bin/sh的,如果那並不是-v'混合不工作)在兩臺機器上打印? – l0b0

+0

這不是正確的方式來遍歷線路總之。如果您的名稱中有一個帶有「*」或其他通配符的文件,它將被shell擴展爲任何匹配的名稱。 @ l0b0給出的while循環方法更安全。 –

+0

...即使如此,你也不能使用換行符安全地劃分文件名,因爲文件名*可以包含*換行符。如果你有一個名爲'./$'的文件,那麼怎麼辦?\ n'/ etc/passwd $'\ n'/ foo.cue'?用NUL字節分隔文件名是唯一安全的方法。 –

回答

0

您可以設置IFS對這樣一個新行:

IFS=" 
" 

$'\n'是ksh93的/慶典/ zsh中的語法,但它不是POSIX語法。在大多數最新系統上,#!/bin/sh指向一個POSIX外殼(儘管這不是POSIX和Solaris 9,10所要求的,10是個例外)。

無論這個shell是否碰巧明白$'\n'不是你應該依賴的東西。如果你想使用$'\n'改變你家當到#!/bin/bash或其他殼之一..


在Ubuntu和Debian Linux和衍生/bin/shdash。與其他一些發行它指向/bin/bash --posix(Bash和POSIX模式)...


還有一點要注意的是,如果你沒有設置IFS不必返回到以前的狀態,這是IFS包含空格,一個TAB和一個換行符。通過取消IFS,字段拆分將會像IFS包含空格,TAB和換行符一樣完成,因此一切看起來都不錯。

取消設置IFS能給併發症,但是,如果這是常規做法

unset IFS  # Unset the IFS variable so it does not exist 
    oldIFS=$IFS  # The old state is supposedly saved 
    IFS=:   # IFS is set to some string 
    IFS=$oldIFS  # Now IFS is set to the empty string, which means no field 
        # splitting is performed at all 
+0

謝謝,解決了所有問題。我不知道殼是不是bash。 – davidgnin

+0

不客氣..我添加了一些關於此的更多文本.. – Scrutinizer

1

根本不需要循環。這應該做你想要什麼:

find . -name *.cue -print0 | xargs -0 -n1 dirname | sort --unique 

如果你真的要循環的結果,you should use while rather than for

while IFS= read -r line; do 
    printf '%s\n' "$line" 
done < "$file" 

my_script | while IFS= read -r line; do 
    printf '%s\n' "$line" 
done 

在回過頭來看看這個問題,關於拆分文字n字符,它可能是你的Ubuntu機器上的/bin/sh不支持$'' bashism

+1

中有描述。還有一種更好的方法來執行dirname,使用具有'-printf'(它有一個格式運算符直接發出dirname)的查找。 –

+0

...這樣做,你可以輸入'sort'爲NUL-delimited,所以你可以使用'sort -z'(或任何GNU擴展名),以及更安全的'IFS = read -r -d''行'。 –

+0

循環的主體是一個例子。我不想只是打印行,抱歉的解釋不好。感謝您的關於和時間的信息。 – davidgnin