我有以下脚本,它将递归地替换文件和目录中的所有空格:
################### SETUP VARIABLES #######################
number=0 # Number of renamed.
number_not=0 # Number of not renamed.
IFS=$'\n'
array=( `find ./ -type d` ) # Find catalogs recursively.
######################## GO ###############################
# Reverse cycle.
for (( i = ${#array[@]}; i; )); do
# Go in to catalog.
pushd "${array[--i]}" >/dev/null 2>&1
# Search of all files in the current directory.
for name in *
do
# Check for spaces in names of files and directories.
echo "$name" | grep -q " "
if [ $? -eq 0 ]
then
# Replacing spaces with underscores.
newname=`echo $name | sed -e "s/ /_/g"`
if [ -e $newname ]
then
let "number_not +=1"
echo " Not renaming: $name"
else
# Plus one to number.
let "number += 1"
# Message about rename.
echo "$number Renaming: $name"
# Rename.
mv "$name" "$newname"
fi
fi
done
# Go back.
popd >/dev/null 2>&1
done
echo -en "\n All operations is complited."
if [ "$number_not" -ne "0" ]
then echo -en "\n $number_not not renamed."
fi
if [ "$number" -eq "0" ]
then echo -en "\n Nothing been renamed.\n"
elif [ "$number" -eq "1" ]
then echo -en "\n $number renamed.\n"
else echo -en "\n Renamed files and catalogs: $number\n"
fi
exit 0
它的工作原理是用目录填充数组:
array=( `find ./ -type d` ) # Find catalogs recursively.
如果我想强制这个脚本在特定目录中工作,我可以这样做吗?
array=( `find /my/start/directory/ -type d` ) # Find catalogs recursively.
我在这里询问(而不是仅仅运行它),因为我想仔细检查它是否正确,我不想意外地重命名服务器上的每个文件!
答案1
您可以通过注释掉命令mv
并运行它来测试您建议的更改的脚本。脚本中发生的事情太多了,我无法立即说没问题,但是如果当前脚本有效(显然没有包含换行符的目录名称,或者数组array
将被破坏,或者名称从破折号开始,这可能会造成混淆mv
,并且echo
在一些地方)然后我冒险猜测它会没问题。
递归地将目录和其他文件的文件名中的空格替换为下划线:
topdir=.
find "$topdir" -depth -name "* *" -exec bash -c '
for pathname do
# $pathname will have at least one space in it
newname=${pathname##*/} # get basename
newname=${newname// /_} # replace spaces with underscores
printf "Would move %s to %s\n" "$pathname" "${pathname%/*}/$newname"
# mv "$pathname" "${pathname%/*}/$newname"
done' bash {} +
这将找到$topdir
其名称中或下方至少包含一个空格的任何内容。它会收集这些路径名并将它们提供给内联bash
脚本。该脚本将提取每个路径名的文件名部分,并用下划线替换空格。为了安全起见,实际mv
操作被注释掉。
该-depth
选项在这里是必要的,因为我们不想重命名尚未访问的目录。有了它,find
将对目录层次结构进行深度优先遍历。
使用的参数替换:
${variable##*/}
:删除 值中最后一个斜杠之前的所有内容variable
。或多或少与 相同$( basename "$variable" )
。${variable%/*}
: 删除最后一个斜杠之后的所有内容。或多或少与 相同$( dirname "$variable" )
。${variable//pattern/replacement}
:替换值中pattern
与匹配的所有内容(这是扩展)replacement
variable
bash
不检查新文件名是否已存在。这可以很容易地在内部脚本中完成bash
,例如
if [ -e "${pathname%/*}/$newname" ]; then
printf "Will not rename %s, new name exists\n" "$pathname" >&2
else
printf "Would move %s to %s\n" "$pathname" "${pathname%/*}/$newname"
# mv "$pathname" "${pathname%/*}/$newname"
fi
测试:
$ tree
.
|-- a directory
| `-- yet another file
|-- script.sh
|-- some file
`-- some other file
1 directory, 4 files
$ sh script.sh
Would move ./some file to ./some_file
Would move ./some other file to ./some_other_file
Would move ./a directory/yet another file to ./a directory/yet_another_file
Would move ./a directory to ./a_directory
有关的: