AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 1537955
Accepted
Don Carpenter
Don Carpenter
Asked: 2025-01-13 03:30:58 +0800 CST2025-01-13 03:30:58 +0800 CST 2025-01-13 03:30:58 +0800 CST

如何使用脚本更改名称中包含空格的文件名

  • 772

我的 Ubuntu 22.04 系统上的 ~home 下(在许多子目录中)有一些文件。我相信大多数带空格的文件名最初来自 Windows。

我使用以下find命令查找有问题的文件

查找 .-name "* *"

有什么方法可以将名称更改为在名称中当前包含空格的所有文件中包含 _ 或其他字符?

例如我想改变

MSC 机脚订单.pdf

到

MSC_机器_脚顺序.pdf

使用 find 命令,我确定有大约 600 个文件需要更改其名称,因此我希望采用某种自动化的方式来更改名称。

当我运行某些脚本时,带有空格的文件名会导致问题。

提前感谢您的帮助。

bash
  • 3 3 个回答
  • 771 Views

3 个回答

  • Voted
  1. Best Answer
    choroba
    2025-01-13T03:51:02+08:002025-01-13T03:51:02+08:00

    您可以使用参数扩展将 或空格替换为下划线:

    find -name '* *' -exec bash -c 'mv "$1" "${1// /_}"' -- {} \;
    
    • ${1// /_}意思是“用下划线替换第一个参数中的每个空格(请参阅中的参数扩展man bash)。
    • bash -c从第一个非选项参数运行命令。此处的命令是mv用下划线替换空格的命令。
    • 命令参数之后的第一个参数bash -c现在并不重要,因此我使用了--。其余参数设置为命令的位置参数。
    • find -exec对找到的每个文件执行命令。{}被文件名替换,最后的\;表示find命令的结束位置。因此,find 调用bash -c并发送文件名作为第一个参数,因此可以重命名。

    需要这个复杂的咒语来保留第一个参数中的空格mv。

    如果您也想重命名子目录,则需要使用-depthand-execdir而不是-exec(否则,目录名称会发生​​变化,并且 find 无法再找到它来处理其内容)。

    请注意,更改文件的名称也可能会导致问题 - 如果程序期望存在具有给定名称的文件,则更改该名称可能会导致程序失败。

    • 16
  2. Peter Cordes
    2025-01-13T18:16:12+08:002025-01-13T18:16:12+08:00

    perl-rename aka renameakaprename非常适合模式替换文件重命名。请参阅https://francopasut.netlify.app/post/linux-rename-confusion/ re:您可以找到此命令的各种名称,并且 util-linux 还曾经发布过rename不使用正则表达式的不同命令。快速浏览后,我认为 Ubuntu 现在将其作为 提供rename。从旧的手册页(来自 Trusty)来看,当时它是perl软件包的一部分;如果情况仍然如此,则您已经安装了它。

    它需要一个 perl 语句来应用于其命令行上的每个文件名。该s/regex/replacement/ 运算符隐式地对(当前行,在本例中为当前文件名)进行操作,因此非常有用。(如果您想在路径中匹配和替换,$_可以使用模式分隔符。)有关 perl 运算符的详细信息,请参阅https://linux.die.net/man/1/perlop。s{pat}{rep}/s//

    对于您的情况,只需 prename 's/ /_/g' 一次对任意数量的文件运行即可。与 sed 类似,/g修饰符会替换匹配的每一个出现位置。使用find -execdir可确保仅看到文件名,而不是目录名,因为无论是否已重命名prename,尝试移动foo bar/x y.txt到都会失败(源目录或目标目录都不存在)。foo_bar/x_y.txtfoo bar/

       find -depth  -name '* *'  -execdir prename -i  's/ /_/g' {} +
    

    -i在覆盖文件之前提示。如果您不打算覆盖任何内容,这通常是一个好主意。它还有一个-naka--dry-run选项。

    我还没有检查find手册页,了解-depth在递归过程中重命名目录是否有必要。在这种情况下,这样做不会有什么坏处,所以我把它包括进去了。


    choroba 的答案是 fork+exec bash,mv对于每个要重命名的文件。 prename只会进行一点文本处理和rename(2)系统调用。更重要的是,对于一次性交互使用,它是一个更简单的命令行。

    公平地说,我确实不得不-execdir在目录包含空格的情况下使用它,这是我在写这个答案的过程中才想到的。我不确定-depth我们的答案是否有必要;我认为无论哪种方式都适用。

    在一个更简单的情况下,所有文件都在一个目录中,您只需 prename -i 's/ /_/g' *\ *使用一个将文件名与空格匹配的 glob 表达式即可。

    或者启用 Bash set -o extglob,prename ... **/*\ *进行递归匹配。但这会让 prename 看到目录名称;如果它们包含空格,它将无法工作,除非您使 perl 代码更复杂,例如分离出基本名称,修改它,然后将其重新添加。或者您可以运行它几次,直到您不再收到错误,因为目录会重命名,因此下一个深度级别将成功。

    • 4
  3. steeldriver
    2025-01-14T09:40:54+08:002025-01-14T09:40:54+08:00

    如果您切换到 zsh,那么您可以使用贡献的 zmv 模块:

    % autoload -Uz zmv        # normally this would go in your user's ~/.zshrc
    
    % zmv -n '(**/)(* *)(#q.D)' '$1${2// /_}'
    

    (-n仅用于测试 - 当您确信所建议的重命名操作正确时,请将其删除)。

    (“globstar”)运算**符使模式匹配像find命令一样递归下降到子目录中。前两组括号将目录和文件名捕获到单独的编号变量中,这些变量可用于替换字符串,而第三组(#q.D)是glob 限定符,其中

    • .将匹配限制为纯文本文件(如find命令的-type f)

    • D包括(隐藏)“点文件”(为了与您原来的find表达保持一致 - 如果您不需要匹配此类文件,则可以省略它)。

    替换$1${2// /_}将未修改的目录部分与修改后的文件名连接起来 -'$1${2:gs/ /_}'如果您愿意,您也可以使用历史样式的扩展来编写。

    参见man zshcontrib和man zshexpn。

    • 0

相关问题

  • 同时复制到两个位置

  • 如何在 shell 脚本中创建选择菜单?

  • 从 bash 迁移到 zsh [关闭]

  • bashrc 还是 bash_profile?

  • 备份 bash 脚本未压缩其 tarball

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve