递归查找多个文件并在linux中重命名

ras*_*hok 60 linux bash shell scripting suse

我有类似的文件a_dbg.txt, b_dbg.txt ...Suse 10系统中.我想编写一个bash shell脚本,它应该通过从中删除"_dbg"来重命名这些文件.

谷歌建议我使用rename命令.所以,我执行命令rename _dbg.txt .txt *dbg*CURRENT_FOLDER

我的实际CURRENT_FOLDER包含以下文件.

CURRENT_FOLDER/a_dbg.txt
CURRENT_FOLDER/b_dbg.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt
Run Code Online (Sandbox Code Playgroud)

执行rename命令后,

CURRENT_FOLDER/a.txt
CURRENT_FOLDER/b.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt
Run Code Online (Sandbox Code Playgroud)

它没有递归,如何使这个命令重命名所有子目录中的文件.喜欢XXYY我将有这么多的子目录,其名称是不可预测的.而且我CURRENT_FOLDER也会有一些其他文件.

kam*_*uel 114

您可以使用find递归查找所有匹配的文件:

$ find . -iname "*dbg*" -exec rename _dbg.txt .txt '{}' \;
Run Code Online (Sandbox Code Playgroud)

编辑:什么'{}'\;是谁?

-exec参数使find rename对于找到的每个匹配文件都执行.'{}'将替换为文件的路径名.最后一个标记,\;只是标记exec表达式的结尾.

所有这些都在find的手册页中很好地描述:

 -exec utility [argument ...] ;
         True if the program named utility returns a zero value as its
         exit status.  Optional arguments may be passed to the utility.
         The expression must be terminated by a semicolon (``;'').  If you
         invoke find from a shell you may need to quote the semicolon if
         the shell would otherwise treat it as a control operator.  If the
         string ``{}'' appears anywhere in the utility name or the argu-
         ments it is replaced by the pathname of the current file.
         Utility will be executed from the directory from which find was
         executed.  Utility and arguments are not subject to the further
         expansion of shell patterns and constructs.
Run Code Online (Sandbox Code Playgroud)

  • 我得到“查找:重命名:没有这样的文件或目录” (6认同)
  • @BartekPacia `rename` 是一个unix util(检查https://www.gnu.org/software/gnulib/manual/html_node/rename.html)。该错误表明您的计算机上未安装它。对于 macOS(通常是这种情况),您可以使用“brew install rename”解决此问题。 (5认同)
  • 对于那些得到"Bareword"的人来说......"不允许在"严格的潜艇"中使用......",试试:`找到.-iname"*BUILD*" - exec rename's/_dbg.txt/.txt /''{}'\;` (4认同)
  • 我检查了它,它仅适用于文件,不适用于目录。 (2认同)

小智 13

为了递归重命名,我使用以下命令:

find -iname \*.* | rename -v "s/ /-/g"
Run Code Online (Sandbox Code Playgroud)

  • 这在 Ubuntu 18.10 上对我不起作用,因为“rename”尝试重命名整个路径,如果更改父目录,则会失败。您必须仅对基本名称进行操作,如下所示:/sf/ask/1157910771/#54163971 并首先使用 `-深度`。 (5认同)

gle*_*man 12

用bash:

shopt -s globstar nullglob
rename _dbg.txt .txt **/*dbg*
Run Code Online (Sandbox Code Playgroud)

  • 好的解决方案 我必须使用`shopt -s globstar nullstar`启用这些bash选项.对于在MacOS上通过`brew install rename`安装的重命名工具,我不得不``rename -s oldStuff newStuff**/*` (5认同)

小智 12

我编写的小脚本用递归方式替换.txt扩展名为/ tmp和子目录下的.cpp扩展名的所有文件

#!/bin/bash

for file in $(find /tmp -name '*.txt')
do
  mv $file $(echo "$file" | sed -r 's|.txt|.cpp|g')
done
Run Code Online (Sandbox Code Playgroud)

  • 破法!请不要在$(查找...)中执行`for file.请参阅[为什么不应解析ls(1)的输出](http://mywiki.wooledge.org/ParsingLs). (5认同)

Cir*_*四事件 7

find -execdir rename 也适用于基本名称的非后缀替换

/sf/answers/1157916931/仅适用于后缀,但这适用于基名上的任意正则表达式替换:

PATH=/usr/bin find . -depth -execdir rename 's/_dbg.txt$/_.txt' '{}' \;
Run Code Online (Sandbox Code Playgroud)

或仅影响文件:

PATH=/usr/bin find . -type f -execdir rename 's/_dbg.txt$/_.txt' '{}' \;
Run Code Online (Sandbox Code Playgroud)

-execdircd仅在基本名称上执行之前先进入目录。

在 Ubuntu 20.04 上测试,找到 4.7.0,重命名 1.10。

方便又安全的帮手

find-rename-regex() (
  set -eu
  find_and_replace="$1"
  PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
    find . -depth -execdir rename "${2:--n}" "s/${find_and_replace}" '{}' \;
)
Run Code Online (Sandbox Code Playgroud)

GitHub 上游.

使用连字符“-”替换空格“-”的示例用法。

空运行显示什么将重命名为什么而不实际执行它:

find-rename-regex ' /-/g'
Run Code Online (Sandbox Code Playgroud)

进行替换:

find-rename-regex ' /-/g' -v
Run Code Online (Sandbox Code Playgroud)

命令说明

该真棒-execdir选项做了cd到该目录执行之前rename的命令,不像-exec

-depth 确保重命名首先发生在孩子身上,然后发生在父母身上,以防止丢失父目录的潜在问题。

-execdir 是必需的,因为重命名在非基本名称输入路径中不能很好地发挥作用,例如以下失败:

rename 's/findme/replaceme/g' acc/acc
Run Code Online (Sandbox Code Playgroud)

PATH需要的黑客,因为-execdir有一个很讨厌的缺点:find极其固执己见,拒绝做任何事情-execdir,如果您有任何相对路径在您的PATH环境变量,例如./node_modules/.bin,与失败:

find:相对路径'./node_modules/.bin'包含在PATH环境变量中,与find的-execdir动作结合使用是不安全的。请从 $PATH 中删除该条目

另见:https : //askubuntu.com/questions/621132/why-using-the-execdir-action-is-insecure-for-directory-which-is-in-the-path/1109378#1109378

-execdirPOSIX的 GNU 查找扩展rename基于 Perl 并且来自rename包。

重命名前瞻解决方法

如果您的输入路径不是来自find,或者您已经受够了相对路径的烦恼,我们可以使用一些 Perl 前瞻来安全地重命名目录,如下所示:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'
Run Code Online (Sandbox Code Playgroud)

我还没有找到一个方便的模拟为-execdir具有xargshttps://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686

sort -r要求,以确保文件有其各自的目录后,由于较长的路径都较短的具有相同前缀之后。

在 Ubuntu 18.10 中测试。

  • 对我有用。这个解决方案应该得到更高的投票。 (5认同)

Man*_*Tai 6

上面的脚本可以写成一行:

find /tmp -name "*.txt" -exec bash -c 'mv $0 $(echo "$0" | sed -r \"s|.txt|.cpp|g\")' '{}' \;
Run Code Online (Sandbox Code Playgroud)