Linux 在命令行和 Xargs 中批量重命名文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10972002/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 06:46:26  来源:igfitidea点击:

Batch renaming files in command line and Xargs

linuxshellunixcommand-linexargs

提问by Cripto

So, I have the following structure:

所以,我有以下结构:

.
..
a.png
b.png 
c.png

I ran a command to resize them

我运行了一个命令来调整它们的大小

ls | xargs -I xx convert xx -resize xx.jpg

Now my dir looks like this

现在我的目录看起来像这样

.
..
a.png.jpg
a.png
b.png.jpg
b.png
c.png.jpg
c.png

The firs question is, how do i rename the file so that I can just have one extension. Not two. (basically, how do I clean up my original mistake)?

The second question is, in the future, using xargs, how do I change the extension of the file simular to second command?

第一个问题是,我如何重命名文件,以便我只能有一个扩展名。不是两个。(基本上,我如何清理我原来的错误)?

第二个问题是,将来使用xargs,如何将simular 文件的扩展名更改为第二个命令?

采纳答案by Tim Pote

how do i rename the file so that I can just have one extension.

我如何重命名文件,以便我只能有一个扩展名。

cd dir/with/messedup/files

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done

in the future, using xargs, how do I change the extension of the file simular to second command?

将来,使用 xargs,如何将类似文件的扩展名更改为第二个命令?

To my knowledge, that can't be done. The best way to do it would be to use a for-loop with parameter substitution much like the one above:

据我所知,这是做不到的。最好的方法是使用与上面类似的参数替换的 for 循环:

for file in *.png; do
  convert "$file" -resize "${file%.png}.jpg"
done

If you have files in subdirectories that you want converted, then you can pipe findto a while readloop:

如果子目录中有要转换的文件,则可以通过管道find传输到while read循环:

find . -type f -name '*.png' |
while read file; do
  convert "$file" -resize "${file%.png}.jpg"
done

NOTE:It's generally considered a bad ideato use the output of lsin a shell script. While your example might have worked fine, there are lot's of examples where it doesn't. For instance, if your filenames happened to have newlines in them (which unix allows), lsprobably won't escape those for you. (That actually depends on your implementation, which is another reason not to use lsin scripts; it's behavior varies greatly from one box to the next.) You'll get more consistent results if you either use findin a while-read loop or file globbing (e.g. *.png) in a for loop.

注意:在 shell 脚本中使用 的输出通常被认为是一个坏主意ls。虽然您的示例可能运行良好,但有很多示例却没有。例如,如果您的文件名中碰巧有换行符(unix 允许),则ls可能不会为您转义。(这实际上取决于您的实现,这是不在ls脚本中使用的另一个原因;它的行为从一个框到另一个框有很大差异。)如果您find在 while-read 循环或文件通配中使用,您将获得更一致的结果(例如*.png)在 for 循环中。

回答by Matej

To clean up your error, try the renameutility. Check the manpage for details.

要清除错误,请尝试使用该rename实用程序。查看联机帮助页了解详细信息。

In your case, you'd do rename '.png.jpg' '.jpg' ./*if your current directory is set appropriately.

在您的情况下,rename '.png.jpg' '.jpg' ./*如果您的当前目录设置适当,您就会这样做。

Since you have convertavailable, I'm assuming you have mogrifytoo (imagemagicksuite). Whenever I want to do this, I copy the files into a different directory and use mogrifyinstead. I usually need this only for resizing, but if you change the image format aswell, mogrifywill handle the filenames (make new files with proper filenames).

既然你convert有空,我假设你也有mogrifyimagemagick套房)。每当我想这样做时,我都会将文件复制到不同的目录中并使用mogrify。我通常只需要它来调整大小,但是如果您还更改图像格式,mogrify将处理文件名(使用正确的文件名制作新文件)。

You would use it as mogrify -format jpg -resize [size] ./*.png. I'm not sure what -resizewithout geometry arguments is supposed to do. It isn't documented and doesn't work on my machine.

您可以将其用作mogrify -format jpg -resize [size] ./*.png. 我不确定-resize没有几何参数应该做什么。它没有记录并且在我的机器上不起作用。

As Tim Pote reasoned, I don't think you can make xargs handle filenames and extensions separately.

正如 Tim Pote 所说,我认为您不能让 xargs 分别处理文件名和扩展名。

回答by Schleis

This can be also be done with xargsand sedto change the file extension.

这也可以通过xargssed更改文件扩展名来完成。

ls | grep \.png$ | sed 'p;s/\.png/\.jpg/' | xargs -n2 mv

You can print the original filename along with what you want the filename to be. Then have xargs use those two arguments in the move command. For the one-liner, I also added a grep to filter out anything not a *.png file.

您可以打印原始文件名以及您想要的文件名。然后让 xargs 在 move 命令中使用这两个参数。对于单行,我还添加了一个 grep 来过滤掉任何不是 *.png 文件的内容。

回答by Paul J

I'm late to this party by about 3 years, I just had a similar problem which I figured out myself. I had a list of png files which I converted using inkscape, because ImageMagick's svg support is poor.

我参加这个聚会晚了大约 3 年,我刚刚遇到了类似的问题,我自己也发现了这个问题。我有一个使用inkscape转换的png文件列表,因为ImageMagick的svg支持很差。

I originally converted them by doing:

我最初通过执行以下操作转换它们:

find . -name "*.svg" -exec inkscape {} --export-png={}.png

Which of course led to the same issue like posted above.

这当然导致了上面发布的相同问题。

file1.svg
file1.svg.png
file2.svg
file2.svg.png
file3.svg
file3.svg.png
file4.svg
file4.svg.png

I wanted to rename *.svg.png to *.png, this is what I wound up with...

我想将 *.svg.png 重命名为 *.png,这就是我的结局......

find . -name "*.svg.png" -print0 | sed 's/.svg.png//g' | xargs -0 -I namePrefix mv namePrefix.svg.png namePrefix.png

This does three things:

这做了三件事:

  1. find in this directory files named *.svg.png, the -print0 prints to standard output
  2. sed modifies the standard output, basically swap .svg.png with nothing, so I'd get: file1/file2/file3/file4
  3. xargs -0 to get the data from sed, -I references the filename w/o the extension, then mv original filename to new filename. The word namePrefix isn't anything special, just wanted to make it clear.
  1. 在此目录中找到名为 *.svg.png 的文件,-print0 打印到标准输出
  2. sed 修改标准输出,基本上没有交换 .svg.png,所以我会得到:file1/file2/file3/file4
  3. xargs -0 从 sed 获取数据,-I 引用不带扩展名的文件名,然后将原始文件名转换为新文件名。namePrefix 这个词没什么特别的,只是想说清楚。

EDIT

编辑

I realize now this is the most convoluted way to do this. One can simply use the rename command.

我现在意识到这是最复杂的方法。可以简单地使用重命名命令。

rename 's/svg\.png/.png/' *

回答by Dethe

Coming late to the party, but here's how you can rename files with xargs. Say you have a bunch of files named fileN.svg.png and you want to name them fileN.png where N could be a series of integers:

迟到了,但这里是您如何使用 xargs 重命名文件的方法。假设您有一堆名为 fileN.svg.png 的文件,并且您想将它们命名为 fileN.png,其中 N 可以是一系列整数:

ls *.svg.png | xargs basename -s .svg.png | xargs -I {} mv {}.svg.png {}.png

ls *.svg.png | xargs basename -s .svg.png | xargs -I {} mv {}.svg.png {}.png

The first xargs uses basename to strip off both .svg and.png to get a just filenameN. The second xargs receives that bare name and uses replacement to rename the file.

第一个 xargs 使用 basename 去除 .svg.png 以获得一个 just filenameN. 第二个 xargs 接收该裸名称并使用替换来重命名文件。

回答by joshperry

My solution is similar to many of the xarg solutions, and particularly similar to Schleis'.

我的解决方案类似于许多 xarg 解决方案,尤其类似于 Schleis 的解决方案。

The difference here is a full regex manipulation with match references, and sed commands that properly ignore files that don't match so you don't need to prefilter your listing.

这里的区别在于完整的正则表达式操作与匹配引用,以及正确忽略不匹配文件的 sed 命令,因此您无需预先过滤您的列表。

This is also safe for files with spaces and shell meta.

这对于带有空格和 shell 元的文件也是安全的。

Change \2in the replacement to any desired extension.

\2将替换更改为任何所需的扩展名。

ls |
sed -nE 's/Rick\.and\.Morty\.(S03E[0-9]{2})\..*(\.[a-z0-9]{3})/"&" "Rick and Morty "/;T;p' |
xargs -n 2 mv

Explanation

解释

The -narg tell's sed not to print anything by default, the Tcommand says skip to the end of the script if the previous scommand didn't do a replacement, the pcommand prints the pattern space (only hit if the scommand matches).

-nARG告诉战略经济对话不打印默认情况下的话,就是T命令的意思是跳到脚本结束时,如果前面的s命令没有做的替代品,该p命令打印模式空间(只打了,如果s命令匹配)。

The &in the replacement is a reference to the contents of the original filename match.

&在替换是将原始文件名匹配的内容的参考。

If we replace mvin the command with bash -c 'echo "run($#) $@"' bashthen we can see the number of times mvwould be called, and with parameter count and value:

如果我们mv在命令中替换为,bash -c 'echo "run($#) $@"' bash我们可以看到mv调用的次数,以及参数计数和值:

$ ls |
  sed -nE 's/Rick\.and\.Morty\.(S03E[0-9]{2})\..*(\.[a-z0-9]{3})/"&" "Rick and Morty "/;T;p' |
  xargs -n 2 bash -c 'echo "run($#) $@"' bash
run(2) Rick.and.Morty.S03E02.720p.HDTV.x264-BATV.mkv Rick and Morty S03E02.mkv
run(2) Rick.and.Morty.S03E03.720p.HDTV.x264-BATV.mkv Rick and Morty S03E03.mkv
run(2) Rick.and.Morty.S03E04.720p.HDTV.x264-BATV.mkv Rick and Morty S03E04.mkv
run(2) Rick.and.Morty.S03E05.HDTV.x264-BATV[ettv].mkv Rick and Morty S03E05.mkv
run(2) Rick.and.Morty.S03E06.720p.HDTV.x264-BATV.mkv Rick and Morty S03E06.mkv
run(2) Rick.and.Morty.S03E06.HDTV.x264-BATV.mkv Rick and Morty S03E06.mkv
run(2) Rick.and.Morty.S03E07.720p.HDTV.x264-BATV[ettv].mkv Rick and Morty S03E07.mkv
run(2) Rick.and.Morty.S03E08.720p.HDTV.x264-BATV.mkv Rick and Morty S03E08.mkv
run(2) Rick.and.Morty.S03E09.720p.HDTV.x264-BATV.mkv Rick and Morty S03E09.mkv
run(2) Rick.and.Morty.S03E10.720p.HDTV.x264-BATV.mkv Rick and Morty S03E10.mkv

回答by xsilen T

find ./xx -name "*.png" -print0 |sed 's/.png$//g'|xargs -0 -I% mv %.png %.jpg

find ./xx -name "*.png" -print0 |sed 's/.png$//g'|xargs -0 -I% mv %.png %.jpg

回答by SergioAraujo

My attempt from: https://www.tecmint.com/linux-image-conversion-tools/

我的尝试来自:https: //www.tecmint.com/linux-image-conversion-tools/

ls -1 *.png | xargs -n 1 bash -c 'convert "
parallel convert '{}' '{.}.jpg' ::: *.png
" "${0%.png}.jpg"'

Using parallel

使用并行

find . -maxdepth 1 -name '*.png' -print0 | sed 's/.png//g' | xargs -0 -I% -n 1 -P 8 convert -quality 100 %.png %.jpg

回答by Alexey K.

After some investigation on similar task here is my code:

经过对类似任务的一些调查,这里是我的代码:

##代码##

Reasoning:

推理:

  • renaming will not compress the file (so use convertinstead of mv)
  • ls \.png$ | xargswill not deal with spaces in the path/filename
  • find .will search in sub-folders, so use -maxdepth 1
  • convertdoesn't use available CPUs so -P8(or -P other)
  • sedwithout 'g'at the end will not substitute all files (only one)
  • sed 's/.png//g'will leave no extension (basename could also work but didn't after -print0)
  • parallel- potentially better solution but didn't work on my Ubuntu 18.04 bash 4.4
  • %is the smallest common symbol for substitution (compare to {} xx namePrefix)
  • -n2parameter is good for xargsbut didn't work with -print0properly (nnumber of entries to take and pass after xargs)
  • -quality 100default magic quality is 92 (which is fine), here 100% to avoid loosing anything
  • 重命名不会压缩文件(所以使用convert代替mv
  • ls \.png$ | xargs不会处理路径/文件名中的空格
  • find .将在子文件夹中搜索,所以使用 -maxdepth 1
  • convert不使用可用的 CPU,所以-P8(或-P other
  • sed没有'g'在最后不会替换所有文件(只有一个)
  • sed 's/.png//g'不会留下任何扩展名(basename 也可以工作,但之后没有-print0
  • parallel- 可能是更好的解决方案,但在我的 Ubuntu 18.04 bash 4.4 上不起作用
  • %是替换的最小常用符号(与 相比{} xx namePrefix
  • -n2参数适用于xargs但不能正常-print0工作(n要获取和传递的条目数xargs
  • -quality 100默认魔法质量是 92(很好),这里是 100% 以避免丢失任何东西