【问题标题】:How to match strings in file names and rename file according to string?如何匹配文件名中的字符串并根据字符串重命名文件?
【发布时间】:2015-04-04 03:35:01
【问题描述】:

我有许多文件名中包含匹配字符串的文件。

foostring.bar
barstring.bar
fuustring.bar
aha_foostring.abc
meh_barstring.abc
lol_fuustring.abc
...

我需要找到带有匹配字符串的 bar 和 abc 文件,并将 *.bar-files 基本名称重命名为 *.abc-files 的样子。也就是说,添加一个字符串前缀。

我正在寻找的结果应该是这样的:

aha_foostring.bar
meh_barstring.bar
lol_fuustring.bar
aha_foostring.abc
meh_barstring.abc
lol_fuustring.abc
...  

澄清编辑:*.abc 文件中的字符串始终位于最后一个下划线_ 和点. 之前。字符串仅包含字母和数字。前缀可以包含任意数量的字符和任意类型的字符,包括_ 和. 这意味着我还需要考虑下面的示例。

dindongstring.bar
w_h.a.t_e_v_e.r_dingdongstring.abc

我一直在尝试使用 find、prefix 和 basename,但在这里我需要帮助和建议。

谢谢

【问题讨论】:

    标签: linux bash rename


    【解决方案1】:

    我会选择这样的东西: (我相信有更优雅的方法来做到这一点(awk/sed))

    #!/bin/bash
    
    for filename in *.abc
    do
        prefix=${filename%_*}
        searchstring=${filename%.abc}
        searchstring=${searchstring#*_}
        if [[ -f "$searchstring.bar" ]]
        then
            mv "${searchstring}.bar" "${prefix}_${searchstring}.bar"
        fi
    done
    # show the result
    ls -al
    

    很抱歉在您的答案中添加此内容,但由于我已删除我的答案并且您的答案最接近 OP 的需求。 (我不介意......我关心解决方案=)

    编辑:可能这就是 OP 想要的:

    for f in *.abc; do
       prefix=${f%_*}
       bar=${f%.abc}
       bar="${bar##*_}.bar"
       [[ -f "$bar" ]] && mv "$bar" "${prefix}_${bar}"
    done
    

    【讨论】:

    • 因为我处理了数百个具有各种前缀的文件,所以这很有效。唯一的例外是前缀包含“_”字符
    • @user1253164 如果它适合你,你为什么不接受答案?
    • 根据我对_ 和. 的澄清,完全命中感谢你们俩。欣赏它。
    【解决方案2】:

    我建议尝试以下“魔术”:

    $ join -j 2 <(ls -1 . | sed -n '/\.bar/s/^\(.*\)\(\.[^.]\+\)$/\1\2\t\1/p' | sort -k2) <(ls -1 . | sed -n '/\.abc/s/^\(.\+_\)\?\([a-zA-Z0-9]\+\)\(\.[^.]\+\)$/\1\2\3\t\2\t\1/p' | sort -k2) | awk '{print $2 " " $4}' | while read FILE PREFIX; do echo mv -v "$FILE" "$PREFIX$FILE"; done
    mv -v barstring.bar meh_barstring.bar
    mv -v dingdongstring.bar w_h.a.t_e_v_e.r_dingdongstring.bar
    mv -v foostring.bar aha_foostring.bar
    mv -v fuustring.bar lol_fuustring.bar
    

    如果它会显示预期的命令,则在 mv 之前删除 echo 并再次运行以进行更改。

    还要注意,我使用ls -1 . 命令显示当前目录的文件,可能您需要更改目录或在包含文件的目录中运行命令。

    小解释:

    该代码背后的想法是为 .bar 和 .abc 文件创建成对的文件名通用部分:

    $ ls -1 . | sed -n '/\.bar/s/^\(.*\)\(\.[^.]\+\)$/\1\2\t\1/p' | sort -k2
    barstring.bar   barstring
    dingdongstring.bar  dingdongstring
    foostring.bar   foostring
    fuustring.bar   fuustring
    $ ls -1 . | sed -n '/\.abc/s/^\(.\+_\)\?\([a-zA-Z0-9]\+\)\(\.[^.]\+\)$/\1\2\3\t\2\t\1/p' | sort -k2
    meh_barstring.abc   barstring   meh_
    w_h.a.t_e_v_e.r_dingdongstring.abc  dingdongstring  w_h.a.t_e_v_e.r_
    aha_foostring.abc   foostring   aha_
    lol_fuustring.abc   fuustring   lol_
    

    如您所见,第二个字段是通用部分。之后,我们通过公共部分将这些列表连接在一起,只留下 .abc 文件名和前缀:

    $ join -j 2 <(ls -1 . | sed -n '/\.bar/s/^\(.*\)\(\.[^.]\+\)$/\1\2\t\1/p' | sort -k2) <(ls -1 . | sed -n '/\.abc/s/^\(.\+_\)\?\([a-zA-Z0-9]\+\)\(\.[^.]\+\)$/\1\2\3\t\2\t\1/p' | sort -k2) | awk '{print $2 " " $4}'
    

    barstring.bar meh_ dingdongstring.bar w_h.a.t_e_v_e.r_ foostring.bar aha_ fuustring.bar 哈哈_

    最后一步是通过添加适当的前缀来重命名文件。

    【讨论】:

    • 获取 sed:无法读取文件名:没有这样的文件...。感谢您的详细说明和 oneliner
    • 我认为filesnames 是一个带有文件名的文件。我已经更新了从当前目录获取文件名的单行程序,并且还考虑了 w_h.a.t_e_v_e.r_dingdongstring.abc 之类的名称
    猜你喜欢
    • 2016-11-10
    • 2022-09-25
    • 2017-10-27
    • 2019-02-12
    • 2011-12-27
    • 2014-04-22
    • 2018-04-10
    • 2017-10-11
    • 1970-01-01
    相关资源
    最近更新 更多