查找多个文件并在Linux中重命名它们


72

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

Google建议我使用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

执行rename命令后,

CURRENT_FOLDER/a.txt
CURRENT_FOLDER/b.txt
CURRENT_FOLDER/XX/c_dbg.txt
CURRENT_FOLDER/YY/d_dbg.txt

它不是递归执行的操作,如何使此命令重命名所有子目录中的文件。LikeXXYY我将有很多子目录,这些子目录的名称不可预测。而且我CURRENT_FOLDER还将拥有一些其他文件。


5
我知道了Bareword "..." not allowed while "strict subs" in use at (eval 1) line 1.
Albert Hendriks 2015年

2
为什么不仅仅重命名-r存在,而是使我们的生活更轻松,而不是使用繁琐的解决方法?
neverMind9

Answers:


131

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

$ find . -iname "*dbg*" -exec rename _dbg.txt .txt '{}' \;

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

-exec参数使findrename对找到的每个匹配文件执行。'{}'将被替换为文件的路径名。最后一个标记\;仅用于标记exec表达式的结尾。

手册页中对找到的所有内容进行了很好的描述:

 -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.

@kamituel谢谢。我正在学习linux,并且使用过几次却不知道这是什么意思。谢谢你的解释。您能告诉我-iname吗?并且我们可以使用上述命令(在Centos 7中)作为find . -type f "*dbg*" -exec rename "_dbg.txt" ".txt" * {} \;
Syed Mudabbir

我检查了它,它仅适用于目录中没有的文件。
Syed Mudabbir '16

我多次收到此错误:Illegal octal digit '9' at (user-supplied code), at end of line。我已经尝试过使用单引号,双引号和不引号作为参数rename。具体来说,我正在尝试替换0123-MISC0123_AB_MISC。这是我的命令 find . -iname "*0123-MISC*" -exec rename 0123-MISC 0123_AB_MISC {} \;
涡流

8
对于那些获得帮助的人Bareword "..." not allowed while "strict subs" in use at ...,请尝试:find . -iname "*BUILD*" -exec rename 's/_dbg.txt/.txt/' '{}' \;
jsand

3
我得到find: rename: No such file or directory
鲍尔泰克PACIA

15

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

find -iname \*.* | rename -v "s/ /-/g"

对还原备份文件也很有用。find -iname \*.* | rename -v -f "s/\.bak//g"
Paolo

我的重命名没有-v。您在Mac OS X上吗?我是Ubuntu 16.
Katastic Voyage,

-v在我发布“重命名”工具时相当于--verbose;对结果并不重要。请输入“人名”以进一步说明。
甘丹'18

1
这对我在Ubuntu 18.10上不起作用,因为它rename尝试重命名整个路径,并且如果更改父目录将失败。取而代之的是,您只能对基本名称进行操作,如下所示:stackoverflow.com/questions/16541582/…并首先使用深入了解-depth
西罗Santilli郝海东冠状病六四事件法轮功

默认-f也是动力,找不到
斯科特


13

用bash:

shopt -s globstar nullglob
rename _dbg.txt .txt **/*dbg*

5
很好的解决方案。我必须使用启用这些bash选项shopt -s globstar nullstar。对于通过brew install renameMacOS安装的重命名工具,我必须做rename -s oldStuff newStuff **/*
Xander Dunn

4

find -execdir rename

https://stackoverflow.com/a/16541670/895245仅直接适用于后缀,但这将适用于基名上的任意正则表达式替换:

PATH=/usr/bin find . -depth -execdir rename 's/_dbg.txt$/_.txt' '{}' \;

或仅影响文件:

PATH=/usr/bin find . -type f -execdir rename 's/_dbg.txt$/_.txt' '{}' \;

-execdir首先cd进入目录,然后仅对基本名称执行。

在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}" '{}' \;
)

GitHub上游

用连字符'-'替换空格''的示例用法。

试运行,显示无需实际操作即可将其重命名为以下内​​容:

find-rename-regex ' /-/g'

执行替换:

find-rename-regex ' /-/g' -v

命令说明

与相比,真棒-execdir选项cd在执行rename命令之前会对目录执行a操作-exec

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

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

rename 's/findme/replaceme/g' acc/acc

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' '{}'

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

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

在Ubuntu 18.10中测试。


1
为我工作。该解决方案应被投票较高。
Paul Chris Jones

3

上面的代码可以写成一行:

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

1
@steven尝试使用此查找。-name“ * .txt” -exec bash -c'mv $ 0 $(echo“ $ 0” | sed -r“ s / .txt / .cpp / g”)''{}'\;
xxbinxx

为每个文件打开/执行一个新的shell非常昂贵(缓慢),因此我通常不这样做。
Binarus

0

如果您只想重命名并且不介意使用外部工具,则可以使用rnm。该命令将是:

#on current folder
rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' *

-dp -1 将使其递归到所有子目录。

-fo 表示仅文件模式。

-ssf '_dbg' 搜索文件名中带有_dbg的文件。

-rs '/_dbg//' 用空字符串替换_dbg。

您也可以使用CURRENT_FOLDER的路径运行以上命令:

rnm -dp -1 -fo -ssf '_dbg' -rs '/_dbg//' /path/to/the/directory

0

您可以在下面使用它。

rename --no-act 's/\.html$/\.php/' *.html */*.html

我的重命名没有--no-act,Ubuntu16。您在Mac OS X上吗?
Katastic Voyage,

我也是。未知选项:在Ubuntu 17.10上不起作用,我不使用Mac OS.no-act是空运行选项。
井上智文

-3

经典解决方案:

for f in $(find . -name "*dbg*"); do mv $f $(echo $f | sed 's/_dbg//'); done

4
这完全被打破了。拜托,不要这样做。
gniourf_gniourf

~/tmp$ mkdir a && cd a/ && touch 1_dbg.txt && cd .. ~/tmp$ for f in $(find . -name "*dbg*"); do mv $f $(echo $f | sed 's/_dbg//'); done ~/tmp$ cd a/ ~/tmp/a$ l total 8 drwxrwxr-x 2 repu1sion repu1sion 4096 Sep 17 21:17 . drwxrwxr-x 3 repu1sion repu1sion 4096 Sep 17 21:17 .. -rw-rw-r-- 1 repu1sion repu1sion 0 Sep 17 21:17 1.txt
2015年

1
也许它似乎有效,但是它与包含空格或glob字符的文件名中断。您说这是一个经典的解决方案,但很有可能是您想出的解决方案,但是它显示了可怕的错误(很抱歉,您可能会在教科书中加入这行代码,作为不采取措施的示例;练习:算一下错误数)。
gniourf_gniourf

1
for f in $(find ....):不要这样做!它以包含空格或glob字符的文件名中断;此外,find还有-exec很可能会被使用的选项;或者,for f in *_dbg*; do或者如果您要使用递归Glob,请for f in **/*_dbg; do使用shopt -s globstar
gniourf_gniourf

2
最后,一个更好的解决办法是:shopt -s globstar nullglob; for f in **/*_dbg*; do mv -- "$f" "${f/_dbg}"; done
gniourf_gniourf
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.