2017-08-19 52 views
0

我試圖刪除文件名中的空格並替換它們。sed/awk - 刪除文件名中的空格

輸入:

echo "File Name1.xml File Name3 report.xml" | sed 's/[[:space:]]/__/g' 

但是輸出

File__Name1.xml__File__Name3__report.xml 

所需的輸出

File__Name1.xml File__Name3__report.xml 
+2

哪裏有文件名來自何處?可以指示Awk對換行符進行分隔,然後可以更容易地在模式中進行匹配。 – linden2015

+0

文件名是否具有相同的'.xml'擴展名? –

+0

是的,他們都是'.xml'文件 – Deano

回答

1

您在問題的標題中名爲awk,不是嗎?

$ echo "File Name1.xml File Name3 report.xml" | \ 
> awk -F'.xml *' '{for(i=1;i<=NF;i++){gsub(" ","_",$i); printf i<NF?$i ".xml ":"\n" }}' 
File_Name1.xml File_Name3_report.xml 
$ 
  • -F'.xml *'指示awk分裂上的正則表達式,所請求的擴展加上0或多個空格
  • 環路{for(i=1;i<=NF;i++)被用於其中輸入線(s)是所有字段執行(是)分裂 - 注意,最後一個字段是無效的(這是接下來的最後一個擴展名),但我們要考慮到這一點...
    的循環體
    • gsub(" ","_", $i)替代的空間所有出現在當前領域強調,通過循環變量作爲索引i
    • printf i<NF?$i ".xml ":"\n"輸出不同的東西,如果i<NF它是一個普通的領域,所以我們追加擴展和一個空格,否則i等於NF,我們只想用換行符終止輸出行。

它並不完美,其追加的最後一個文件名之後的空間。我希望這足夠好...


▶一個d d簡d U m的◀

我想解決:

爲了達到這些目標,我決定換一個殼功能的小腳本,即改變空​​格爲下劃線被命名爲s2u

$ s2u() { awk -F'\.'$1' *' -v ext=".$1" '{ 
> NF--;for(i=1;i<=NF;i++){gsub(" ","_",$i);printf "%s",$i ext (i<NF?" ":"\n")}}' 
> } 
$ echo "File Name1.xml File Name3 report.xml" | s2u xml 
File_Name1.xml File_Name3_report.xml 
$ 

這是一個有點不同(更好?)「CS它不是特殊打印最後一個字段,而是特殊情況下每個字段附加的分隔符,但擴展名分割的想法仍然存在。

+0

感謝您的詳細解答,我已經學到了很多:) – Deano

+1

由於未加密的三元表達式,這將導致某些awk中的語法錯誤,並且當文件名包含printf格式化字符時,它將以加密方式失敗。 'big%slip.xml' - 總是使用'printf'%s「,$ i'而不是'printf $ i'。您可能希望使用'[[:space:]]「,而不是對希望/假定ORS的值進行硬編碼,而是在printf的末尾逐字使用'ORS'而不是'\ n」'。 +'而不是''''-F和gsub正則表達式。 –

+0

有些'awk's沒有正則表達式字符類......我不想使用默認的'ORS',我想要一個換行符!也就是說,我已經在三元表達式中實現了關於括號的建議,正確使用了'printf',也糾正了最後一個空白的bug。 TX – gboffi

0

這似乎是一個很好的開始,如果文件名不劃定:

((?:\S.*?)?\.\w{1,})\b 

(  // start of captured group 
(?:  // non-captured group 
\S.*? // a non-white-space character, then 0 or more any character 
)?  // 0 or 1 times 
\.  // a dot 
\w{1,} // 1 or more word characters 
)  // end of captured group 
\b  // a word boundary 

您必須查看PCRE模式如何轉換爲shell模式。或者,它可以從Python/Perl/PHP腳本運行。

Demo

-1

你可以使用rename

rename --nows *.xml 

這將替換XML文件的所有空間在當前文件夾用_

有時是不帶--nows選項,這樣你就可以使用搜索和替換:

rename 's/[[:space:]]/__/g' *.xml 

最終,你可以使用--dry-run,如果你只想打印文件名,而無需編輯的名字。

+0

請閱讀問題。 OP沒有要求重命名文件。也許他們會改變這個問題,但現在你回答了另一個問題。 – gboffi

+1

我不知道最後想做什麼(爲此我給了'--dry-run')。但是從'刪除文件名中的空格'我明顯地假設我的答案即使不是被接受的答案,仍然是主題... –

+0

OP問題涉及包含文件名的字符串,'--dry-run'選項如何提供幫助他們?在我看來,你的答案應該被重新表述爲一個評論,_「在重命名這些文件後,你不會有任何機會嗎?」_ – gboffi

0

假設您要求如何重命名文件名,並且不要刪除因某種其他原因而使用的文件名列表中的空格,這是漫長而短暫的。很長的路使用sed。短路使用重命名。如果你不想重命名文件,你的問題還不清楚,應該修改。

如果目標是簡單地獲取xml文件名列表並用sed更改它們,則底層示例是如何執行該操作。

目錄內容:

ls -w 2 
bob is over there.xml 
fred is here.xml 
greg is there.xml 

cd [directory with files] 
shopt -s nullglob 
a_glob=(*.xml); 
for ((i=0;i< ${#a_glob[@]}; i++));do 
    echo "${a_glob[i]}"; 
done 
shopt -u nullglob 
# output 
bob is over there.xml 
fred is here.xml 
greg is there.xml 

# then rename them 
cd [directory with files] 
shopt -s nullglob 
a_glob=(*.xml); 
for ((i=0;i< ${#a_glob[@]}; i++));do 
    # I prefer 'rename' for such things 
    # rename 's/[[:space:]]/_/g' "${a_glob[i]}"; 
    # but sed works, can't see any reason to use it for this purpose though 
    mv "${a_glob[i]}" $(sed 's/[[:space:]]/_/g' <<< "${a_glob[i]}"); 
done 
shopt -u nullglob 

結果:

ls -w 2 
bob_is_over_there.xml 
fred_is_here.xml 
greg_is_there.xml 

通配的是你想在這裏,因爲在名稱空間的什麼。

然而,這的確是一個複雜的解決方案,而實際上所有你需要做的是:

cd [your space containing directory] 
rename 's/[[:space:]]/_/g' *.xml 

,就是這樣,你就大功告成了。

另一方面,如果你正在嘗試創建一個文件名列表,你肯定會想要globbing方法,如果你只是修改語句,也會做你想做的事情,也就是使用sed更改輸出文件名稱。

如果你的目標是要改變文件名進行輸出的目的,而不是重命名的實際文件:

cd [directory with files] 
shopt -s nullglob 
a_glob=(*.xml); 
for ((i=0;i< ${#a_glob[@]}; i++));do 
    echo "${a_glob[i]}" | sed 's/[[:space:]]/_/g'; 
done 
shopt -u nullglob 
# output: 
bob_is_over_there.xml 
fred_is_here.xml 
greg_is_there.xml