繁体   English   中英

如何使用 bash 脚本替换文件名中的空格

[英]How to replace spaces in file names using a bash script

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

$ 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

我用:

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

使用rename (又名prename ),这是一个 Perl 脚本,可能已经在您的系统上。 分两步进行:

find . -name "* *" -type d | rename 's/ /_/g'    # do the directories first
find . -name "* *" -type f | rename 's/ /_/g'

基于Jürgen 的回答,并且能够使用/usr/bin/rename的“Revision 1.5 1998/12/18 16:16:31 rmb1”版本(Perl 脚本)在单个范围内处理多层文件和目录:

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

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

你可以使用 Doug Harple 的detox

detox -r <folder>

查找/重命名解决方案。 重命名是 util-linux 的一部分。

您需要首先降低深度,因为空白文件名可以是空白目录的一部分:

find /tmp/ -depth -name "* *" -execdir rename " " "_" "{}" ";"

你可以使用这个:

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

重击 4.0

#!/bin/bash
shopt -s globstar
for file in **/*\ *
do 
    mv "$file" "${file// /_}"       
done

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

在 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'

对于那些在 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   

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

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 _

这个做的有点多。 我用它来重命名我下载的种子(没有特殊字符(非 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,$_);
    }
}

这是一个合理大小的 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
)

递归版本的一个简单替代方法是逐步增加 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 

我发现了这个脚本,它可能很有趣:)

 IFS=$'\n';for f in `find .`; do file=$(echo $f | tr [:blank:] '_'); [ -e $f ] && [ ! -e $file ] && mv "$f" $file;done;unset IFS

我只是为自己的目的制作一个。 您可以将其用作参考。

#!/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

对于名为 /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

我对这个问题的解决方案是一个 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

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

使用以下命令在文件名和目录名中用下划线替换空格。

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

如果您只需要通过替换所有空格来重命名一个目录中的文件。 然后您可以将此命令与rename.ul一起使用:

for i in *' '*; do rename.ul ' ' '_' *; done

这只会在当前目录中找到文件并重命名它们 我有这个别名。

find ./ -name "* *" -type f -d 1 | perl -ple '$file = $_; $file =~ s/\s+/_/g; rename($_, $file);

替换下划线或其他内容

 FileName.split(" ").join("_")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM