谁能推荐一个安全的解决方案来递归地用下划线替换从给定根目录开始的文件和目录名中的空格?例如:

$ tree
.
|-- a dir
|   `-- file with spaces.txt
`-- b dir
    |-- another file with spaces.txt
    `-- yet another file with spaces.pdf

就变成:

$ tree
.
|-- a_dir
|   `-- file_with_spaces.txt
`-- b_dir
    |-- another_file_with_spaces.txt
    `-- yet_another_file_with_spaces.pdf

当前回答

这是一个(相当冗长的)find -exec解决方案,它将“文件已经存在”警告写入stderr:

function trspace() {
   declare dir name bname dname newname replace_char
   [ $# -lt 1 -o $# -gt 2 ] && { echo "usage: trspace dir char"; return 1; }
   dir="${1}"
   replace_char="${2:-_}"
   find "${dir}" -xdev -depth -name $'*[ \t\r\n\v\f]*' -exec bash -c '
      for ((i=1; i<=$#; i++)); do
         name="${@:i:1}"
         dname="${name%/*}"
         bname="${name##*/}"
         newname="${dname}/${bname//[[:space:]]/${0}}"
         if [[ -e "${newname}" ]]; then
            echo "Warning: file already exists: ${newname}" 1>&2
         else
            mv "${name}" "${newname}"
         fi
      done
  ' "${replace_char}" '{}' +
}

trspace rootdir _

其他回答

find . -depth -name '* *' \
| while IFS= read -r f ; do mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr ' ' _)" ; done

一开始我没有把它弄好,因为我没有想到目录。

我对这个问题的解决方案是一个bash脚本:

#!/bin/bash
directory=$1
cd "$directory"
while [ "$(find ./ -regex '.* .*' | wc -l)" -gt 0 ];
do filename="$(find ./ -regex '.* .*' | head -n 1)"
mv "$filename" "$(echo "$filename" | sed 's|'" "'|_|g')"
done

只需在执行脚本后将您想要应用脚本的目录名称作为参数。

你可以使用道格·哈普尔的排毒

detox -r <folder>

你可以用这个:

find . -depth -name '* *' | while read fname 

do
        new_fname=`echo $fname | tr " " "_"`

        if [ -e $new_fname ]
        then
                echo "File $new_fname already exists. Not replacing $fname"
        else
                echo "Creating new file $new_fname to replace $fname"
                mv "$fname" $new_fname
        fi
done

递归版本的一个简单替代方法是逐步增加for循环的范围(n个子级别n次,与每一级别上的子目录数量无关)。即从最外层的目录运行这些。

for f in *; do mv "$f" "${f// /_}"; done 

for f in */*; do mv "$f" "${f// /_}"; done 

for f in */*/*; do mv "$f" "${f// /_}"; done 

要检查/理解正在执行的操作,请在上述步骤前后运行以下操作。

for f in *;do echo $f;done 

for f in */*;do echo $f;done 

for f in */*/*;do echo $f;done