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

获取文件和目录列表:

要递归地操作文件,与globs相比,使用find是更好的解决方案。我建议您在开始操作文件名之前,先用文件名填充bash数组。此外,我认为一步一个脚印,目录然后文件,这样做是谨慎的。您不想重命名目录,然后在重命名文件时发现该文件不存在。同样重要的是,出于同样的原因,脚本在文件系统层次结构上的更深层次上工作(因此使用了下面的sort)。

在列表上操作:

一旦你有了列表,你就可以调用一个通用的shell函数来进行文件或目录名的规范化和重命名。请注意正确引用姓名以获得所需信息的重要性。这一点非常重要,因为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

注意:实现脚本来为任何非字母数字的内容"做正确的事情"似乎并不简单。例如,我不知道如何处理文件或目录名中的句点、预先存在的下划线或其他"常规"允许的字符。

以通用的方式识别不需要的/特殊的字符也是一个问题。在国际语言环境中,它更为复杂。我不知道有什么简单的说法可以"只允许英文字母表中的数字或字符"。如果有人有想法,请发表答案。

您也可以尝试递归运行该命令(可能有一种方法可以在不调用相同脚本的情况下完成此操作,但我现在无法使其工作):

假设此脚本在您的路径中或此处/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退出并在需要时进行重命名。

在bash的最新版本中,您可以使用

for f in **

您可能需要设置globstar选项才能使其工作:

shopt -s globstar

如果文件名不能包含制表符或换行符(注意引号):

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

另请参阅Shell 中的文件名和路径名

编辑:对不起,我忘记了空白。我的标准处理方式是读取循环(假设文件名称中不能有换行符)
find | {
read f
while [ -n "$f" ]
do
    # process "$f" (always with the quotes)
    read f
done
}

最新更新