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
Batch renaming files in command line and Xargs
提问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 find
to a while read
loop:
如果子目录中有要转换的文件,则可以通过管道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 ls
in 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), ls
probably won't escape those for you. (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 (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 rename
utility. 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 convert
available, I'm assuming you have mogrify
too (imagemagick
suite). Whenever I want to do this, I copy the files into a different directory and use mogrify
instead. 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).
既然你convert
有空,我假设你也有mogrify
(imagemagick
套房)。每当我想这样做时,我都会将文件复制到不同的目录中并使用mogrify
。我通常只需要它来调整大小,但是如果您还更改图像格式,mogrify
将处理文件名(使用正确的文件名制作新文件)。
You would use it as mogrify -format jpg -resize [size] ./*.png
. I'm not sure what -resize
without 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 xargs
and sed
to change the file extension.
这也可以通过xargs
和sed
更改文件扩展名来完成。
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:
这做了三件事:
- find in this directory files named *.svg.png, the -print0 prints to standard output
- sed modifies the standard output, basically swap .svg.png with nothing, so I'd get: file1/file2/file3/file4
- 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.
- 在此目录中找到名为 *.svg.png 的文件,-print0 打印到标准输出
- sed 修改标准输出,基本上没有交换 .svg.png,所以我会得到:file1/file2/file3/file4
- 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 \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 "/;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告诉战略经济对话不打印默认情况下的话,就是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 "/;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
convert
instead ofmv
) ls \.png$ | xargs
will not deal with spaces in the path/filenamefind .
will search in sub-folders, so use-maxdepth 1
convert
doesn't use available CPUs so-P8
(or-P other
)sed
without'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
)-n2
parameter is good forxargs
but didn't work with-print0
properly (n
number of entries to take and pass afterxargs
)-quality 100
default 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% 以避免丢失任何东西