Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 在Bash中从文件名中提取最后一个数字_String_Bash - Fatal编程技术网

String 在Bash中从文件名中提取最后一个数字

String 在Bash中从文件名中提取最后一个数字,string,bash,String,Bash,我有很多文件要重命名。几乎所有这些文件都是图片 源文件名类似于: DSC08828.JPG => 08828.JPG 20130412_0001.JPG => 0001.JPG 0002.JPG => 0002.JPG IMG0047.jpg => 0047.jpg DSC08828_1.JPG => Is a duplicate should be ignored ... DSC08828_9.JPG

我有很多文件要重命名。几乎所有这些文件都是图片

源文件名类似于:

DSC08828.JPG       => 08828.JPG
20130412_0001.JPG  => 0001.JPG
0002.JPG           => 0002.JPG
IMG0047.jpg        => 0047.jpg
DSC08828_1.JPG     => Is a duplicate should be ignored
...
DSC08828_9.JPG     => Is a duplicate should be ignored
我所要做的就是以尽可能快的方式获取最后一个数字,后跟文件扩展名(因为我们谈论的是近600.000张图片)

所以我想得到字符串,从第一个出现的至少两个数字开始,从点后面的右边直到第一个非数字字符。如果右边只有一个数字,则应忽略该文件

for x in ./*.JPG ./*.jpg; do
    y=$(echo "$x"|sed '/[^0-9]//g');
    echo "$x" "$y";
done
虽然我没有给你最后的答案,但这应该让你开始,并说明如何处理你描述的任务的技巧

根据以后要对文件执行的操作,还可以组合
find
grep
,例如
find-键入f | grep-v'\.[0-9]\.
以筛选包含
\
的所有文件,该文件后跟一个数字,后跟一个点(未测试,可能需要转义)
-v
用于否定由
grep
过滤的匹配项

因为在你的帖子中,你告诉过你要重命名过滤器,并提供了一个过滤一些文件的例子,我猜你需要两者:首先,过滤你不想要的文件,然后在
for
循环中重命名过滤过的文件

sed -nr 's%^.*[^0-9]([0-9]{2,}\.[^.]+)$%\1%p' < <(find ./ -type f -iname '*.JPG')
虽然我没有给你最后的答案,但这应该让你开始,并说明如何处理你描述的任务的技巧

根据以后要对文件执行的操作,还可以组合
find
grep
,例如
find-键入f | grep-v'\.[0-9]\.
以筛选包含
\
的所有文件,该文件后跟一个数字,后跟一个点(未测试,可能需要转义)
-v
用于否定由
grep
过滤的匹配项

因为在你的帖子中,你告诉过你要重命名过滤器,并提供了一个过滤一些文件的例子,我猜你需要两者:首先,过滤你不想要的文件,然后在
for
循环中重命名过滤过的文件

sed -nr 's%^.*[^0-9]([0-9]{2,}\.[^.]+)$%\1%p' < <(find ./ -type f -iname '*.JPG')
虽然我没有给你最后的答案,但这应该让你开始,并说明如何处理你描述的任务的技巧

根据以后要对文件执行的操作,还可以组合
find
grep
,例如
find-键入f | grep-v'\.[0-9]\.
以筛选包含
\
的所有文件,该文件后跟一个数字,后跟一个点(未测试,可能需要转义)
-v
用于否定由
grep
过滤的匹配项

因为在你的帖子中,你告诉过你要重命名过滤器,并提供了一个过滤一些文件的例子,我猜你需要两者:首先,过滤你不想要的文件,然后在
for
循环中重命名过滤过的文件

sed -nr 's%^.*[^0-9]([0-9]{2,}\.[^.]+)$%\1%p' < <(find ./ -type f -iname '*.JPG')
虽然我没有给你最后的答案,但这应该让你开始,并说明如何处理你描述的任务的技巧

根据以后要对文件执行的操作,还可以组合
find
grep
,例如
find-键入f | grep-v'\.[0-9]\.
以筛选包含
\
的所有文件,该文件后跟一个数字,后跟一个点(未测试,可能需要转义)
-v
用于否定由
grep
过滤的匹配项


因为在你的帖子中,你告诉你要重命名过滤器,并提供了一个过滤一些文件的例子,我猜你需要两个:首先,过滤你不想要的文件,然后在
for
循环中重命名过滤过的文件。

sed-nr's%^.[^0-9]([0-9]{2,}.[^.]+)$%\1%p<
sed-nr's%^.[^0-9]([0-9]{2,}.]$%\1%p'<
sed-nr's%^.[^0-9]([0-9]{2,}.[^.]+)$%\1%p'<
sed-nr's%^.[^0-9]([0-9]{2,}.[^.]+)$\1%p'<这里有一个使用
sed
的方法,可以提高性能:

sed -nr 's%^.*[^0-9]([0-9]{2,}\.[^.]+)$%\1%p' < <(find ./ -type f -iname '*.JPG')
ls *.{JPG,jpg} | \
sed '
    /_[1-9]*\./d;    # first drop any line that appears to be a duplicate   
    /^[0-9]*\./d;    # drop any line that does not need to be renamed   
    s/\(.*\)/\1 \1/; # save the original filename by duplicating the pattern space
    s/ .*_/ /;       # remove any leading characters followed by and including _ in the new filename
    s/ [A-Z]*/ /;    # remove any leading capital letters from the new filename
    s/^/mv -i /;     # finally insert mv command at the beginning of the line
'
当您对命令感到满意时,请输入到
sh

输入:

0002.JPG
20130412_0001.JPG
DSC08828.JPG
DSC08828_1.JPG
DSC08828_9.JPG
IMG0047.jpg
mv -i 20130412_0001.JPG 0001.JPG
mv -i DSC08828.JPG 08828.JPG
mv -i IMG0047.jpg 0047.jpg
输出:

0002.JPG
20130412_0001.JPG
DSC08828.JPG
DSC08828_1.JPG
DSC08828_9.JPG
IMG0047.jpg
mv -i 20130412_0001.JPG 0001.JPG
mv -i DSC08828.JPG 08828.JPG
mv -i IMG0047.jpg 0047.jpg

下面是一种使用
sed
的方法,它可以提高性能:

ls *.{JPG,jpg} | \
sed '
    /_[1-9]*\./d;    # first drop any line that appears to be a duplicate   
    /^[0-9]*\./d;    # drop any line that does not need to be renamed   
    s/\(.*\)/\1 \1/; # save the original filename by duplicating the pattern space
    s/ .*_/ /;       # remove any leading characters followed by and including _ in the new filename
    s/ [A-Z]*/ /;    # remove any leading capital letters from the new filename
    s/^/mv -i /;     # finally insert mv command at the beginning of the line
'
当您对命令感到满意时,请输入到
sh

输入:

0002.JPG
20130412_0001.JPG
DSC08828.JPG
DSC08828_1.JPG
DSC08828_9.JPG
IMG0047.jpg
mv -i 20130412_0001.JPG 0001.JPG
mv -i DSC08828.JPG 08828.JPG
mv -i IMG0047.jpg 0047.jpg
输出:

0002.JPG
20130412_0001.JPG
DSC08828.JPG
DSC08828_1.JPG
DSC08828_9.JPG
IMG0047.jpg
mv -i 20130412_0001.JPG 0001.JPG
mv -i DSC08828.JPG 08828.JPG
mv -i IMG0047.jpg 0047.jpg

下面是一种使用
sed
的方法,它可以提高性能:

ls *.{JPG,jpg} | \
sed '
    /_[1-9]*\./d;    # first drop any line that appears to be a duplicate   
    /^[0-9]*\./d;    # drop any line that does not need to be renamed   
    s/\(.*\)/\1 \1/; # save the original filename by duplicating the pattern space
    s/ .*_/ /;       # remove any leading characters followed by and including _ in the new filename
    s/ [A-Z]*/ /;    # remove any leading capital letters from the new filename
    s/^/mv -i /;     # finally insert mv command at the beginning of the line
'
当您对命令感到满意时,请输入到
sh

输入:

0002.JPG
20130412_0001.JPG
DSC08828.JPG
DSC08828_1.JPG
DSC08828_9.JPG
IMG0047.jpg
mv -i 20130412_0001.JPG 0001.JPG
mv -i DSC08828.JPG 08828.JPG
mv -i IMG0047.jpg 0047.jpg
输出:

0002.JPG
20130412_0001.JPG
DSC08828.JPG
DSC08828_1.JPG
DSC08828_9.JPG
IMG0047.jpg
mv -i 20130412_0001.JPG 0001.JPG
mv -i DSC08828.JPG 08828.JPG
mv -i IMG0047.jpg 0047.jpg

下面是一种使用
sed
的方法,它可以提高性能:

ls *.{JPG,jpg} | \
sed '
    /_[1-9]*\./d;    # first drop any line that appears to be a duplicate   
    /^[0-9]*\./d;    # drop any line that does not need to be renamed   
    s/\(.*\)/\1 \1/; # save the original filename by duplicating the pattern space
    s/ .*_/ /;       # remove any leading characters followed by and including _ in the new filename
    s/ [A-Z]*/ /;    # remove any leading capital letters from the new filename
    s/^/mv -i /;     # finally insert mv command at the beginning of the line
'
当您对命令感到满意时,请输入到
sh

输入:

0002.JPG
20130412_0001.JPG
DSC08828.JPG
DSC08828_1.JPG
DSC08828_9.JPG
IMG0047.jpg
mv -i 20130412_0001.JPG 0001.JPG
mv -i DSC08828.JPG 08828.JPG
mv -i IMG0047.jpg 0047.jpg
输出:

0002.JPG
20130412_0001.JPG
DSC08828.JPG
DSC08828_1.JPG
DSC08828_9.JPG
IMG0047.jpg
mv -i 20130412_0001.JPG 0001.JPG
mv -i DSC08828.JPG 08828.JPG
mv -i IMG0047.jpg 0047.jpg

对于600000个文件,这肯定会失败,因为您将超过命令行的最大长度:在我的机器上,
getconf ARG_MAX
outputs
2097152
,并且文件至少有5个字符,因此对于600000个文件,这已经超过了最大长度。此外特别是在这里,您真的不需要
ls
!查看您的命令:首先shell看到大括号并展开它;剩下的是
ls*.JPG*.JPG
;然后,它执行路径名扩展并尝试将其馈送到
ls
!没用!无论如何,
ls
会用它做什么?它将对参数进行排序并输出它们。您也可以这样做:
printf'%s\n'*.{JPG,JPG}
。现在,globs在shell中速度很慢,因此使用
find
的方法更合适。关于如何获取文件的新名称的基本问题已经得到了回答。我迭代文件夹中的文件(每天一个文件夹)结构:2013/12/31/bildxxx.jpg,并将它们放置在一个新的结构中,并使用新的名称。@gniourf_gniourf我希望大多数Shell会从stdin中逐行读取命令。你是在暗示那场狂欢吗