2013-03-22 112 views
1

我試圖構建一個腳本,其中的一部分使用'sed'標記文件名到該文件中每行的末尾,然後將輸出轉儲到主列表。 劇本給我找麻煩的一部分,這裏的sed:在變量和正則表達式中使用sed for循環

DIR=/var/www/flatuser 
FILES=$DIR/* 
for f in $FILES 
do 
    echo "processing $f file...." 
    sed -i "s/$/:$f/" $f 
    cat $f >> $DIR/master.txt 
done 

的問題是,「sed的」語句工作的罰款之外循環,但是當我把它放在劇本,我相信這是有解釋美元符號的問題。我已經嘗試過幾乎每一個「和」的組合,以便讓它解釋變量,並且它不斷地在每行末尾放置「$ f」,或者直接失敗。 !任何輸入

+0

@ chepner的回答是點。然而,要補充的另一件事是,你需要對_all_擴展進行雙引號,以使它們對於帶有空格的內容(或glob擴展等)是安全的......例如,「cat」$ f「> >「$ DIR/master.txt」。 – 2013-03-22 16:03:08

+1

呃,更重要的一點 - 如果你只是想要包含在master中的名字。txt,你不應該先在原始文件上使用'sed -i';這樣做意味着您不能多次運行腳本而不添加一個以上的名稱副本,這是一個不幸的限制。 – 2013-03-22 16:15:33

+0

OHHH我明白了什麼是錯的!在一秒鐘內發佈我的答案......暗示這不是美元符號! – pepper 2013-03-22 16:19:45

回答

3

就個人而言,我會做到這一點,像這樣:

dir=/var/www/flatuser 
for f in "$dir"/*; do 
    [[ $f = */master.txt ]] && continue 
    while read -r; do printf '%s:%s\n' "$REPLY" "${f##*/}"; done <"$f" 
done >/var/www/flatuser/master.txt 

它不會修改就地的方式sed -i做你的文件,所以它的安全運行比更(sed -i版本會在每次運行時將文件的名稱添加到文件中,因此每行最後都會有多個文件名副本)。

另外,sed -i不是由POSIX指定的,所以不是所有的操作系​​統都會擁有它。

+0

糟糕。此前的修訂版本實際上並未在循環中輸入「$ f」。 – 2013-03-22 16:16:36

+0

這個答案讓我最接近我要去的地方。我沒有與'sed'結婚,這正是我在我有限的「工具箱」中所擁有的;)。這個問題唯一的問題是它將完整路徑標記到每行的末尾而不僅僅是文件名。嘗試擺弄它,我不'看到從哪裏來。建議? – SteveHNH 2013-03-22 16:28:55

+0

我建議這個答案,在試圖找到'不中'$ F'發生sed'的替換操作的分隔符。 – chepner 2013-03-22 16:30:23

5

你只需要逃跑的美元符號:使殼硬是將其傳遞到sed

sed -i "s/\$/:$f/" "$f" 

要在查爾斯達菲的點擴大約引用變量:

DIR=/var/www/flatuser 
for f in "$DIR"/* 
do 
    echo "processing $f file...." 
    sed -i "s/\$/:${f##*/}/" "$f" 
    cat "$f" >> "$DIR/master.txt" 
done 

如果有任何文件名包含空格,爲時已晚,如果你指定的文件名列表來$FILES做任何事情;您不能再區分屬於文件名的空格和分隔文件名的空格。你可以用一個數組來代替,但是把glob直接放在for循環中會更簡單。這裏是你將如何使用數組:

DIR=/var/www/flatuser 
FILES=("$DIR"/*) 
for f in "${FILES[@]}" 
do 
    echo "processing $f file...." 
    sed -i "s/\$/:${f##*/}/" "$f" 
    cat "$f" >> "$DIR/master.txt" 
done 

對於sed版本不使用-i,這裏有一個方法來顯式處理,以模擬就地編輯所需的臨時文件:

t=$(mktmp sXXXX); sed "s/\$/:$f/" "$f" > "$t"; mv "$t" "$f" && rm "$t" 
+0

感謝您的出色解釋!雖然,當使用上述任何一種方法時,我仍然得到sed錯誤。這是我所看到的,也許這將有助於闡明一些光:'sed:-e表達式#1,字符7:未知選項s''。它運行的文件與此類似:'abc-test1'' abc-test2'。我認爲刪除文件名中的連字符將會有所幫助,但是在完成之後我看不到任何改變。 – SteveHNH 2013-03-22 16:16:34

+0

@pepper關於文件名的路徑分隔符與'sed'的分隔符衝突是正確的。雖然可以使用不同的分隔符,但仍然需要選擇一個不出現在$ f中的代碼,這可能會非常棘手。 – chepner 2013-03-22 16:31:32

+0

從與'sed'命令使用它時的'$ F'值刪除目錄中刪除的'/'作爲分隔符,一個簡單的文件名不能包含'/'的問題。 – chepner 2013-03-22 16:45:41

0

問題不在於美元符號。這就是變量$ f包含一個「/」字符,並且sed正在使用它來分隔表達式。嘗試使用「@」作爲分隔符。

DIR=/var/www/flatuser 
FILES=$DIR/* 
for f in $FILES 
do 
    echo "processing $f file...." 
    sed -i [email protected]"$"@:"$f"@ $f 
    cat $f >> $DIR/master.txt 
done 
+0

現在你確實是有問題的報價,但因爲'$ @'是一個特殊的shell參數:) – chepner 2013-03-22 16:26:46

+0

SED語句是在引號,但我將修改它移動的報價,並確保這個工程 – pepper 2013-03-22 16:27:28

+0

雙報價;參數擴展適用。 – chepner 2013-03-22 16:27:48

0

這是舊的,但也許它可以幫助某人。 爲什麼不BASENAME文件擺脫之前的目錄

DIR=/var/www/flatuser 
FILES=("$DIR"/*) 
for f in "${FILES[@]}" 
do 
    echo "processing $f file...." 
    b=`basename $f` 
    sed -i "s/\$/:${b##*/}/" "$b" 
    cat "$f" >> "$DIR/master.txt" 
done 

沒有測試過的......