任何人都可以推荐一个安全的解决方案,从给定的根目录开始递归地用文件和目录名称中的下划线替换空格吗?例如:
$ 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
答案 0 :(得分:304)
我用:
for f in *\ *; do mv "$f" "${f// /_}"; done
虽然它不是递归的,但它非常快速和简单。我相信这里有人可以将它更新为递归。
${f// /_}
部分利用bash的参数扩展机制用提供的字符串替换参数中的模式。
相关语法为${parameter/pattern/string}
。请参阅:https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html或http://wiki.bash-hackers.org/syntax/pe。
答案 1 :(得分:275)
使用rename
(又名prename
),这是可能已在您系统上的Perl脚本。分两步完成:
find -name "* *" -type d | rename 's/ /_/g' # do the directories first
find -name "* *" -type f | rename 's/ /_/g'
基于Jürgen的答案,能够使用{{1修订版1.5 1998/12/18 16:16:31 rmb1“版本在单个边界中处理多层文件和目录(Perl脚本):
/usr/bin/rename
答案 2 :(得分:96)
find . -depth -name '* *' \
| while IFS= read -r f ; do mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr ' ' _)" ; done
一开始没能把它弄好,因为我没想到目录。
答案 3 :(得分:24)
您可以使用Doug Harple的detox
detox -r <folder>
答案 4 :(得分:11)
查找/重命名解决方案。 重命名是util-linux的一部分。
首先需要降低深度,因为空白文件名可以是空白目录的一部分:
find /tmp/ -depth -name "* *" -execdir rename " " "_" "{}" ";"
答案 5 :(得分:5)
bash 4.0
#!/bin/bash
shopt -s globstar
for file in **/*\ *
do
mv "$file" "${file// /_}"
done
答案 6 :(得分:5)
你可以用这个:
find . -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
答案 7 :(得分:2)
这是一个(非常详细的)find -exec解决方案,它将“file already exists”警告写入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 _
答案 8 :(得分:2)
这个更多一点。我用它来重命名我下载的种子(没有特殊字符(非ASCII),空格,多个点等)。
#!/usr/bin/perl
&rena(`find . -type d`);
&rena(`find . -type f`);
sub rena
{
($elems)=@_;
@t=split /\n/,$elems;
for $e (@t)
{
$_=$e;
# remove ./ of find
s/^\.\///;
# non ascii transliterate
tr [\200-\377][_];
tr [\000-\40][_];
# special characters we do not want in paths
s/[ \-\,\;\?\+\'\"\!\[\]\(\)\@\#]/_/g;
# multiple dots except for extension
while (/\..*\./)
{
s/\./_/;
}
# only one _ consecutive
s/_+/_/g;
next if ($_ eq $e ) or ("./$_" eq $e);
print "$e -> $_\n";
rename ($e,$_);
}
}
答案 9 :(得分:1)
这是一个尺寸合理的bash脚本解决方案
#!/bin/bash
(
IFS=$'\n'
for y in $(ls $1)
do
mv $1/`echo $y | sed 's/ /\\ /g'` $1/`echo "$y" | sed 's/ /_/g'`
done
)
答案 10 :(得分:1)
我在这个脚本周围找到了它可能很有趣:)
IFS=$'\n';for f in `find .`; do file=$(echo $f | tr [:blank:] '_'); [ -e $f ] && [ ! -e $file ] && mv "$f" $file;done;unset IFS
答案 11 :(得分:1)
Naidim的回答的递归版本。
find . -name "* *" | awk '{ print length, $0 }' | sort -nr -s | cut -d" " -f2- | while read f; do base=$(basename "$f"); newbase="${base// /_}"; mv "$(dirname "$f")/$(basename "$f")" "$(dirname "$f")/$newbase"; done
答案 12 :(得分:1)
在macOS
就像选择的答案一样。
brew install rename
#
cd <your dir>
find . -name "* *" -type d | rename 's/ /_/g' # do the directories first
find . -name "* *" -type f | rename 's/ /_/g'
答案 13 :(得分:0)
这只查找当前目录中的文件并重命名。我有这个别名。
find ./ -name "* *" -type f -d 1 | perl -ple '$file = $_; $file =~ s/\s+/_/g; rename($_, $file);
答案 14 :(得分:0)
我只为自己的目的制作一个。 您可以将其用作参考。
#!/bin/bash
cd /vzwhome/c0cheh1/dev_source/UB_14_8
for file in *
do
echo $file
cd "/vzwhome/c0cheh1/dev_source/UB_14_8/$file/Configuration/$file"
echo "==> `pwd`"
for subfile in *\ *; do [ -d "$subfile" ] && ( mv "$subfile" "$(echo $subfile | sed -e 's/ /_/g')" ); done
ls
cd /vzwhome/c0cheh1/dev_source/UB_14_8
done
答案 15 :(得分:0)
对于名为/ files
的文件夹中的文件for i in `IFS="";find /files -name *\ *`
do
echo $i
done > /tmp/list
while read line
do
mv "$line" `echo $line | sed 's/ /_/g'`
done < /tmp/list
rm /tmp/list
答案 16 :(得分:0)
对于那些使用macOS苦苦挣扎的人,先安装所有工具:
brew install tree findutils rename
然后当需要重命名时,为GNU find(gfind)创建一个别名作为find然后运行@Michel Krelin的行:,
alias find=gfind
find . -depth -name '* *' \
| while IFS= read -r f ; do mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr ' ' _)" ; done
答案 17 :(得分:0)
我对这个问题的解决方案是一个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
只需在执行脚本后将要在其中应用脚本的目录名作为自变量即可。
答案 18 :(得分:0)
使用下面的命令将文件名和目录名中的空格替换为下划线。
find -name "* *" -print0 | sort -rz | \
while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done