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

arm*_*ino 244 linux bash filenames whitespace

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

$ tree
.
|-- a dir
|   `-- file with spaces.txt
`-- b dir
    |-- another file with spaces.txt
    `-- yet another file with spaces.pdf
Run Code Online (Sandbox Code Playgroud)

变为:

$ tree
.
|-- a_dir
|   `-- file_with_spaces.txt
`-- b_dir
    |-- another_file_with_spaces.txt
    `-- yet_another_file_with_spaces.pdf
Run Code Online (Sandbox Code Playgroud)

Nai*_*dim 326

我用:

for f in *\ *; do mv "$f" "${f// /_}"; done
Run Code Online (Sandbox Code Playgroud)

虽然它不是递归的,但却非常快速和简单.我相信这里有人可以将它更新为递归.

"$ {f ///_}"部分利用bash的参数扩展机制,用提供的字符串替换参数中的模式.相关语法是"$ {parameter/pattern/string}".请参阅:https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.htmlhttp://wiki.bash-hackers.org/syntax/pe.

  • 简单,在mac中工作.(mac没有'重命名`,而且很难用brew安装它......) (9认同)
  • 很棒的答案.我在*\*中使用`for d 做mv"$ d""$ {d // /}"; 完成了非得分. (6认同)
  • 非常好,在Windows下使用Git Bash (6认同)
  • 只有一个对我有用.有一个upvote! (5认同)
  • `${f// /_}` 是一个 [Bash 变量扩展](http://wiki.bash-hackers.org/syntax/pe),用于[搜索和替换](https://wiki.bash-hackers) .org/syntax/pe#search_and_replace)。- “f”是每个包含空格的文件的“for”循环中的变量。- 第一个“//”表示“全部替换”(不要在第一次出现时停止)。- 那么 `/\_` 的意思是“用下划线替换空格” (4认同)
  • 作为参考,这很容易在 bash 中*成为*递归以使用 `shopt -s globstar` 和 `for f in **/*\ *; 做...`。`globstar` 选项是 bash 的内部选项,而 `rename` 命令是一个常见的 Linux 工具,而不是 bash 的一部分。 (2认同)
  • 有人可以解释这部分为何起作用:$ {f // / _} (2认同)
  • 根据您的解决方案,我将其递归:`while read line ; 执行 mv "$line" "${line// /}" ; 完成 < <(find /path/ -iname "* *")` (2认同)

Pau*_*ce. 290

使用rename(又名prename)Perl脚本,它可能已经在您的系统上.分两步完成:

find -name "* *" -type d | rename 's/ /_/g'    # do the directories first
find -name "* *" -type f | rename 's/ /_/g'
Run Code Online (Sandbox Code Playgroud)

根据于尔根的答案,并能处理文件和目录的多层纵身使用的"修订版1.5 1998年12月18日16时16分31秒1元"的版本/usr/bin/rename(Perl脚本):

find /tmp/ -depth -name "* *" -execdir rename 's/ /_/g' "{}" \;
Run Code Online (Sandbox Code Playgroud)

  • 如果你在OS X上运行它,你需要`brew install rename` (13认同)
  • 这在Centos 7上不起作用,因为rename命令完全不同(它是二进制文件,而不是perl脚本),并且它不接受来自stdin的数据. (6认同)
  • 无需两个步骤:使用深度优先搜索:find dir -depth (5认同)
  • 哦,我刚刚阅读了`rename`联机帮助页(我不知道该工具),我认为你可以通过将`s// _/g`更改为`y// _ /`;-)来优化代码 (3认同)
  • @CpnCrunch 在 RHEL 6.2 和 Cygwin 中相同(`rename --version` 表示`rename from util-linux 2.xx`,但无论如何都是批量重命名的好工具 (2认同)

Mic*_*ker 100

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

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

  • 这必须是我第50次访问此页面以复制和使用您的解决方案.非常感谢你**.我更喜欢你的答案,因为我在Mac上并且没有丹尼斯提出的"重命名"命令. (8认同)

小智 27

你可以使用detoxDoug Harple

detox -r <folder>
Run Code Online (Sandbox Code Playgroud)

  • 太棒了-谢谢Doug Harple! (2认同)

Jür*_*zel 11

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

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

find /tmp/ -depth -name "* *" -execdir rename " " "_" "{}" ";"
Run Code Online (Sandbox Code Playgroud)

  • 这只会在我的跑步中改变 _one_ 空间,所以“go tell fire on the Mountain”变成了“go_tell fire on the Mountain”。 (2认同)

gho*_*g74 6

bash 4.0

#!/bin/bash
shopt -s globstar
for file in **/*\ *
do 
    mv "$file" "${file// /_}"       
done
Run Code Online (Sandbox Code Playgroud)


小智 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
Run Code Online (Sandbox Code Playgroud)


C.K*_*.K. 5

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

Run Code Online (Sandbox Code Playgroud)