2015-04-02 138 views
-1

說,文件'listall'包含目錄列表,我想列出這些目錄中的所有文件,包括目錄路徑。 我在下面寫了一個bash腳本。將變量傳遞給sed,當變量包含斜槓(/)

#!/bin/bash 
\rm listZ 
echo ' ' > listZ 
for i in `cat listall`; ls $i | sed -e '1,$s/^/$i\//g' >> listZ; done 

但是在sed命令中,$ i沒有被替換爲目錄名稱。
我嘗試使用雙引號爲sed命令,但無濟於事。這是在cygwin中。 我該怎麼辦?

+0

使用雙引號代替單引號在sed。 – 2015-04-02 06:34:43

+0

正如我所說,我試過了,在這種情況下它不起作用。 (可能是因爲,如下面的paxdiablo所述,我的變量$ i包含一些'/'字符。 – 2015-04-02 07:34:24

+0

可能在[sed腳本中的shell變量]重複(http://stackoverflow.com/questions/7006910/shell-variables-in- sed-script) – NeronLeVelu 2015-04-02 08:11:34

回答

1

單引號字符串不受變量替換的影響。然而,這是一個簡單的事情來移動變量單引號字符串,如用:

pax> one=1 ; echo ' 
...> 1 
...> 101 
...> 3.14159' | sed 's/'$one'/x/g' 

x 
x0x 
3.x4x59 

在你的情況,這將是:

for i in `cat listall`; do ls $i | sed -e '1,$s/^/'$i'\//g' >> listZ; done 
#             ^^^^ 

請記住, ,根據你的評論,如果你的文件包含特殊的字符sed,他們會給你帶來悲痛。例如,如果它們包含/字符,則需要阻止該命令被seds命令解釋。

或許要做到這一點最簡單的方法是使用一個不同的分隔那可能是在輸入文件:

for i in `cat listall`; do ls $i | sed -e '1,$s?^?'$i'/?g' ; done 
+0

我試過你的例子, 。我很高興看到它,並嘗試相同的,但它不起作用。你可以用shell腳本嘗試它嗎?(例如,包含兩行'/ usr/bin /'和'/ u sr/local/bin /'? – 2015-04-02 07:06:25

+1

@Chan,那是因爲'$ i'變量包含'/'字符,所以會搞砸'sed'命令。我會提供一個更新。 – paxdiablo 2015-04-02 07:17:22

1

DontParseLsDontReadLinesWithFor

您提出的問題可以通過使用雙引號而不是單引號來解決,但是,您需要轉義任何您不打算讓shell解釋的shell元字符(換句話說,必須使用反斜槓 - 在地址範圍1,$中避開美元符號,或在雙引號旁邊使用單引號,並可能更改爲不同的分隔符以應對變量$i; '1,$'"s:^:$i:")的斜槓。

但是您的整個任務可以作爲一個命令執行。

IFS=$'\n' find $(cat listall) -mindepth 1 -maxdepth 2 -print >listZ 

IFS只有嚴格必要的,如果listall包含在其中空格的文件名。您原則上仍然需要轉義任何其他shell元字符(星號,方括號,問號)。更健壯的解決方法是

while read -r directory; do 
    printf '%s\n' "$directory"/* "$directory"/*/* 
done <listall >listZ 

(我誤解你的問題在第一,並承擔listall包含文件名,目錄名無關。我讓我原來的答覆如下。)


sed "s:^:$i/:" listall >listZ 

假設您實際上不需要需要第一行的空白空間(可能會將'1i\ '添加到sed腳本)。地址範圍1,$sed中的默認值,因此指定它是多餘的。因爲每行只能有一個替換,所以標誌也是多餘的(這意味着,將一行中的所有事件替換爲一行,而不是僅替換第一行)。如果在$i中可能有冒號,請使用不同的分隔符。

+0

listall文件僅包含「/ usr/bin」和/ usr/local/bin等目錄名稱,並且不包含這些目錄中的文件名。 – 2015-04-02 07:32:46

+0

答覆已更新;謝謝澄清。 – tripleee 2015-04-02 07:34:09

+0

你的「find $(cat listall)-maxdepth 1 -print> listZ」方法幾乎完成任務(只需少量額外編輯 - 它也會打印目錄名稱..)。我只是爲了好奇而等待paxdiablo的'sed'方法,因爲它不需要額外的人工編輯。順便說一句,結合「'和」「不適合我。 – 2015-04-02 07:44:53

0

正如paxdiablo(並感謝tripleee)所指出的,我的問題是shell變量包含幾個'/'字符,這些字符混淆了sed substitute命令。所以我們可以避免使用另一個分隔符如';'的問題而不是sed的'/'。 所以,正確的做法是

#!/bin/bash 
\rm listZ 
echo ' ' > listZ 
for i in `cat listall`; ls $i | sed 's;^;$i' >> listZ; done 

注意,在我的情況下,該文件listall看起來像

/usr/bin/ 
/usr/local/bin/