2012-07-23 42 views
1

我有這個腳本,只有父文件夾,它不重命名子文件夾和文件 - 我希望得到它剝離所有非數字與_到它。bash重命名空間 - 也做子文件和文件夾以及

#!/bin/bash 
for f in * 
do 
    new="${f// /_}" 
    if [ "$new" != "$f" ] 
    then 
     if [ -e "$new" ] 
     then 
     echo not renaming \""$f"\" because \""$new"\" already exists 
     else 
     echo moving "$f" to "$new" 
     mv "$f" "$new" 
     fi 
    fi 
done 

回答

4

獲取文件和目錄列表:

要對文件進行操作遞歸地使用find與球體相比是更好的解決方案。我建議在開始對它們進行操作之前用文件名填充bash數組。此外,我認爲一次做這一步,目錄然後文件,將是謹慎的。您不想重命名目錄,然後在重命名文件時稍後會發現該文件不存在。由於相同的原因,腳本在文件系統層次結構上逐步深入地工作也很重要(因此使用下面的sort)。

操作上列出:

一旦你的列表,你可以調用一個共同的外殼函數來完成文件或目錄名正火和重命名。請注意正確引用名稱以獲得您想要的內容的重要性。這是非常重要的,因爲bash(或者任何shell)在解析命令行時使用空格作爲字邊界。

腳本:

下面的腳本(名爲./rename_spaces.bash在下面的示例輸出)應該做你想要什麼。要添加自己的怪異字符,請將它們添加到weirdchars變量中。請注意,您需要轉義字符(,例如單引號已被轉義)。如果新文件名存在,腳本會跳過並顯示一條消息。這也意味着它將打印消息以進行不重要的重命名(文件名中沒有原始名稱中的怪異字符)。這可以是惱人的一些人(例如我:-P)

#!/bin/bash 

# set -o xtrace # uncomment for debugging 

declare weirdchars=" &\'" 

function normalise_and_rename() { 
    declare -a list=("${!1}") 
     for fileordir in "${list[@]}"; 
     do 
      newname="${fileordir//[${weirdchars}]/_}" 
      [[ ! -a "$newname" ]] && \ 
      mv "$fileordir" "$newname" || \ 
       echo "Skipping existing file, $newname." 
     done 
} 

declare -a dirs files 

while IFS= read -r -d '' dir; do 
    dirs+=("$dir") 
done < <(find -type d -print0 | sort -z) 

normalise_and_rename dirs[@] 

while IFS= read -r -d '' file; do 
    files+=("$file") 
done < <(find -type f -print0 | sort -z) 

normalise_and_rename files[@] 

這裏是與目錄和文件之前和運行上面的腳本後有名稱空間目錄樹的樣本輸出。

$ tree 
. 
├── dir1 
│ ├── subdir1\ with\ spaces 
│ │ └── file1 
│ └── subdir2\ with\ spaces&weird\ chars' 
│  └── file2 
├── dir2 
│ ├── subdir1\ with\ spaces 
│ │ └── file1\ with\ space 
│ └── subdir2\ with\ spaces 
│  └── file2\ with\ space 
├── dir3 
│ ├── subdir1 
│ │ └── file1 
│ ├── subdir2 
│ │ └── file2 
│ └── subdir3 
│  └── file3 
└── rename_spaces.bash 

10 directories, 8 files 
$ ./rename_spaces.bash 
$ tree 
. 
├── dir1 
│ ├── subdir1_with_spaces 
│ │ └── file1 
│ └── subdir2_with_spaces_weird_chars_ 
│  └── file2 
├── dir2 
│ ├── subdir1_with_spaces 
│ │ └── file1_with_space 
│ └── subdir2_with_spaces 
│  └── file2_with_space 
├── dir3 
│ ├── subdir1 
│ │ └── file1 
│ ├── subdir2 
│ │ └── file2 
│ └── subdir3 
│  └── file3 
└── rename_spaces.bash 

10 directories, 8 files 

注:執行腳本「做正確的事」的任何非字母數字似乎是不平凡的。例如,我不確定如何處理文件或目錄名中的點或預先存在的下劃線或其他「常規」允許的字符。

以通用方式識別不需要/特殊字符也是一個問題。在國際語言環境中它更加複雜。我不知道任何簡單的方式說「允許英語字母表中的數字或字符」。如果有人有想法,請繼續併發布答案。

+0

您好,這對我來說似乎是完美的解決方案。問你是否也可以用_代替任何非字母數字的東西太多了?我有一些口音,文件夾和文件中的符號。 再次感謝。 – thevoipman 2012-07-24 14:54:39

+0

@thevoipman看看我的編輯。我向腳本添加了對任意特殊字符的支持,並添加了關於如何在文本中配置它的註釋。玩的開心。 :) – suvayu 2012-07-24 18:27:57

+0

我重讀你的評論,並試圖改變腳本做正確的事情,非字母數字。但它似乎是不平凡的。在答案結尾閱讀我的筆記。 – suvayu 2012-07-24 18:51:10

0

編輯:對不起,我忘記了空格。我的操作標準的方式,是一個讀循環(假定文件中不能有名字換行)

find | { 
read f 
while [ -n "$f" ] 
do 
    # process "$f" (always with the quotes) 
    read f 
done 
} 
+0

這不起作用,文件名中的空格使它們分開「文件」。所以如果你有一個空格爲「qwe asd」的目錄,f會是「qwe」,然後是「asd」。 – 2012-07-23 23:36:04

+0

@JonLin這是正確的,我正在等待一個解決方案來克服這個問題。 – thevoipman 2012-07-23 23:45:16

+0

好點。我忘記了空白。添加了它 – Sodved 2012-07-24 13:44:33

0

在最近版本的bash,你可以使用

for f in ** 

您可能需要設置globstar爲了選擇,使其工作:

shopt -s globstar 
+0

我在哪裏可以購買那個shopt -s globstar? – thevoipman 2012-07-23 23:44:33

+0

@thevoipman:在第一次使用**之前的任何地方。 – choroba 2012-07-23 23:45:30

+0

下面是我得到的: sh re.sh re.sh:line 2:shop:globstar:無效shell選項名稱 – thevoipman 2012-07-23 23:53:14

1

您也可以嘗試遞歸運行命令(有可能是一個辦法做到這一點,而無需調用相同的腳本,但我不能得到它的工作裏GHT現在):

說這個腳本是在你的路徑,或在這裏/usr/local/bin/remove_spaces.sh

#!/bin/bash 

for f in * 
do 
    if [ -d "$f" ] 
    then 
     cd "$f" 
     /usr/local/bin/remove_spaces.sh 
     cd .. 
    fi 

    new="${f// /_}" 
    if [ "$new" != "$f" ] 
    then 
     if [ -e "$new" ] 
     then 
    echo not renaming \""$f"\" because \""$new"\" already exists 
     else 
    echo moving "$f" to "$new" 
    mv "$f" "$new" 
     fi 
    fi 
done 

所以你基本上是,檢查當前文件f是一個目錄如果是的話,cd到它,並重新運行命令,然後cd退出並根據需要進行重命名。

+0

哇,這會變得更復雜,然後我想。我以爲我可以做一些像mv -R * abc + 1. *然後完成:) b – thevoipman 2012-07-24 00:04:58

+0

@thevoipman我只添加了第一個if塊,其他所有內容與您的腳本相同。 – 2012-07-24 00:07:28

+0

這個爲我工作!整潔和完美! – 2012-12-06 06:53:20

0

如果文件名不能包含製表符,換行符(注意引號):

IFS="$(printf '\n\t')" 
for file in $(find .) ; do 
    COMMAND "$file" ... 
done 

參見Filenames and Pathnames in Shell