【问题标题】:How to split the string with delimiter and swap the substring's position in bash?如何用分隔符分割字符串并在bash中交换子字符串的位置?
【发布时间】:2021-12-17 05:08:35
【问题描述】:

这是场景,

例如,我们有一个名为 a.txt、b.txt、...z.txt 的文件列表。目标是将它们命名为 txt.a,txt.b,txt.c.....txt.z

输入:

a.txt
b.txt
c.txt
...
...
z.txt

输出:

txt.a
txt.b
txt.c
...
...
txt.z

我尝试了这种单线并获得了所需的输出。 单线

ls -l *.txt | awk -F " " '{print $9}' | awk -F "." '{str1 = $2; str2 = "."; str3 = $1; str4 = str1 str2 str3; print str4}'

问: 如果 bash 中还有更好的方法来实现此功能,有人可以帮忙吗?

【问题讨论】:

    标签: bash shell awk split shift


    【解决方案1】:

    假设/理解:

    • 目标是重命名文件(问题提到了Goal is to name them as ...,但没有提到mv 命令...???)
    • 所有文件名都包含一个句点
    • 我们想要切换文件名的前/后部分以创建新文件名
    • 不存在使用新文件名的文件(例如,我们目前没有名为 a.txttxt.a 的文件)

    使用parameter expansion 的一个想法可以让我们消除子流程调用的开销:

    for fname in *.txt
    do
        new_fname="${fname#*.}.${fname%.*}"
        echo mv "${fname}" "${new_fname}"
    done
    

    对于文件名 a.txtb.txtc.txt,这会生成:

    mv a.txt txt.a
    mv b.txt txt.b
    mv c.txt txt.c
    

    一旦 OP 对结果感到满意,就可以删除 echo,脚本应该执行实际的 mv/rename。

    【讨论】:

      【解决方案2】:

      如果基于 Perl 的 rename 命令可用,请尝试:

      rename 's/^([^.]+)\.([^.]+)$/$2.$1/' *.txt
      

      重命名规则是 Perl 的替换表达式 使用正则表达式:

      • ^ 匹配(锚定)文件名的开头。
      • ([^.]+) 匹配除点之外的任何字符序列。 然后匹配的子字符串可以通过 $1 引用,因为周围的括号。
      • \. 匹配一个点。
      • ([^.]+) 再次。现在被$2引用。
      • $ 匹配(锚定)文件名的结尾。
      • $2.$1 是替换部分,交换两个子串 穿过点。

      请注意,有两个名为 rename 的不同命令。一个是 基于Perl,其他的不是。您可以通过以下方式识别它 看到手册页。如果它包含单词perlexpr,它是基于Perl 的。

      【讨论】:

        【解决方案3】:
        for f in [a-z].txt; do mv "$f" "txt.${f%.*}"; done
        

        【讨论】:

          【解决方案4】:

          如果文件名是最后一列,并且文件有一个点,您可以使用单个 awk 在一个点上拆分并反向打印 2 个部分。

          使用$NF 匹配最后一个字段。

          ls -l *.txt | awk '
          {
              split($NF, a, ".")
              print a[2] "." a[1]
          }'
          

          如果拆分后应该有2个部分,您可以查看拆分结果:

          ls -l *.txt | awk '
          {
              n=split($NF, a, ".")
              if (n == 2) print a[2] "." a[1]
          }'
          

          或者作为替代方案,使用 sed 和反向打印的 2 个捕获组,使用 ls -1 每行列出一个文件。

          ls -1 *.txt | sed -E 's/^([^.]+)\.([^.]*)$/\2.\1/'
          

          【讨论】:

          猜你喜欢
          • 2013-11-15
          • 2013-05-03
          • 1970-01-01
          • 2021-06-12
          • 2017-03-25
          • 2011-09-12
          • 2021-09-25
          相关资源
          最近更新 更多