简体   繁体   English

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

[英]Batch renaming files in command line and Xargs

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 文件的扩展名更改为第二个命令?

This can be also be done with xargs and sed to 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.然后让 xargs 在移动命令中使用这两个参数。 For the one-liner, I also added a grep to filter out anything not a *.png file.对于单行,我还添加了一个 grep 来过滤掉任何不是 *.png 文件的内容。

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 find to a while read loop:如果子目录中有要转换的文件,则可以通过管道findwhile read循环:

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

NOTE: It's generally considered a bad idea to use the output of ls in a shell script.注意:在 shell 脚本中使用ls的输出通常被认为是一个坏主意 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), ls probably won't escape those for you.例如,如果您的文件名中碰巧有换行符(unix 允许), ls可能不会为您转义。 (That actually depends on your implementation, which is another reason not to use ls in scripts; it's behavior varies greatly from one box to the next.) You'll get more consistent results if you either use find in a while-read loop or file globbing (eg *.png ) in a for loop. (这实际上取决于您的实现,这是不在脚本中使用ls另一个原因;它的行为从一个框到另一个框有很大差异。)如果您在 while-read 循环中使用find或for 循环中的文件通配(例如*.png )。

Coming late to the party, but here's how you can rename files with xargs.迟到了,但这里是您如何使用 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:假设您有一堆名为 fileN.svg.png 的文件,并且您想将它们命名为 fileN.png,其中 N 可以是一系列整数:

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 .第一个 xargs 使用 basename 去除 .svg.png 以获得一个filenameN The second xargs receives that bare name and uses replacement to rename the file.第二个 xargs 接收该裸名称并使用替换来重命名文件。

To clean up your error, try the rename utility.要清除错误,请尝试rename实用程序。 Check the manpage for details.查看联机帮助页了解详细信息。

In your case, you'd do rename '.png.jpg' '.jpg' ./* if your current directory is set appropriately.在您的情况下,如果您的当前目录设置正确,您将rename '.png.jpg' '.jpg' ./*

Since you have convert available, I'm assuming you have mogrify too ( imagemagick suite).既然你有convert可用,我假设你也有mogrifyimagemagick套件)。 Whenever I want to do this, I copy the files into a different directory and use mogrify instead.每当我想这样做时,我都会将文件复制到不同的目录中并改用mogrify I usually need this only for resizing, but if you change the image format aswell, mogrify will handle the filenames (make new files with proper filenames).我通常只需要它来调整大小,但是如果您还更改图像格式, mogrify将处理文件名(使用正确的文件名制作新文件)。

You would use it as mogrify -format jpg -resize [size] ./*.png .您可以将其用作mogrify -format jpg -resize [size] ./*.png I'm not sure what -resize without geometry arguments is supposed to do.我不确定-resize没有几何参数应该做什么。 It isn't documented and doesn't work on my machine.它没有记录并且在我的机器上不起作用。

As Tim Pote reasoned, I don't think you can make xargs handle filenames and extensions separately.正如 Tim Pote 所说,我认为您不能让 xargs 分别处理文件名和扩展名。

I'm late to this party by about 3 years, I just had a similar problem which I figured out myself.我参加这个聚会晚了大约 3 年,我刚刚遇到了类似的问题,我自己也发现了这个问题。 I had a list of png files which I converted using inkscape, because ImageMagick's svg support is poor.我有一个使用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在此目录中找到名为 *.svg.png 的文件,-print0 打印到标准输出
  2. sed modifies the standard output, basically swap .svg.png with nothing, so I'd get: file1/file2/file3/file4 sed 修改标准输出,基本上没有交换 .svg.png,所以我会得到: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. xargs -0 从 sed 获取数据,-I 引用不带扩展名的文件名,然后将原始文件名转换为新文件名。 The word namePrefix isn't anything special, just wanted to make it clear. 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/' *

After some investigation on similar task here is my code:经过对类似任务的一些调查,这里是我的代码:

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

Reasoning:推理:

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

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 \\2 in 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 \1\2"/;T;p' |
xargs -n 2 mv

Explanation解释

The -n arg tell's sed not to print anything by default, the T command says skip to the end of the script if the previous s command didn't do a replacement, the p command prints the pattern space (only hit if the s command matches). -n arg 告诉 sed 默认不打印任何内容, T命令表示如果前一个s命令没有执行替换,则跳到脚本的末尾, p命令打印模式空间(仅在s命令时命中火柴)。

The & in the replacement is a reference to the contents of the original filename match.替换中的&是对原始文件名匹配内容的引用。

If we replace mv in the command with bash -c 'echo "run($#) $@"' bash then we can see the number of times mv would 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 \1\2"/;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

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 "$0" "${0%.png}.jpg"'

Using parallel使用并行

parallel convert '{}' '{.}.jpg' ::: *.png

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

I like to use following command我喜欢使用以下命令

find ./xx -name "*.png" -type f|while read FILE; do
  mv "$FILE" "$(echo $FILE|sed -e 's/.png$/.jpg/')";
done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM