【问题标题】:Best way to swap first 4 chars with last 4 chars of string?将前 4 个字符与字符串的后 4 个字符交换的最佳方法?
【发布时间】:2014-07-14 14:26:43
【问题描述】:

用字符串的后4个字符交换前4个字符的方法是什么?

例如我有字符串 20140613,我想将其转换为 06132014。

【问题讨论】:

    标签: string bash swap


    【解决方案1】:
    $ f=20140613
    $ g=${f#????}${f%????}
    $ echo $g
    06132014
    

    为了处理较长的字符串,需要以下内容。 (灵感来自 konsolebox 的回答。)

    echo ${f:(-4)}${f:4:${#f} - 8}${f:0:4}
    

    【讨论】:

    • 我喜欢这个,干净简单:) #????指定前 4 和 %????指定最后 4 个?
    • @etan-reisner:我投票支持您的答案,因为它 (1) 将在任何 POSIX shell 中运行,并且 (2) 它完全依赖于内置程序并且不会产生新进程。
    • @user3388884:是的,它叫“参数扩展”,这里有一个权威参考:pubs.opengroup.org/onlinepubs/009695399/utilities/…
    • @user3388884 ? 是任何单个字符的 shell glob。根据 mkalkov 的链接(和 bash 手册页),#% 在变量值的开头和结尾匹配。
    • 不幸的是,如果输入超过 8 个字符,这将不起作用,例如:f=2014abcd0613
    【解决方案2】:

    只需使用子字符串扩展:

    $ STRING=20140613
    $ echo "${STRING:(-4)}${STRING:0:4}"
    06132014
    

    Parameter Expansion

    【讨论】:

    • 简单地说:这就是解决方案。 ;) 太棒了!
    【解决方案3】:

    使用纯 BASH 正则表达式:

    s='20140613'
    
    [[ "$s" =~ ^(.*)([[:digit:]]{4})$ ]] && echo "${BASH_REMATCH[2]}${BASH_REMATCH[1]}"
    06132014
    

    【讨论】:

    • +1,但它太冗长了 :) 我不知道为什么 bash 至少不能为 BASH_REMATCH 选择一个更短的名称。
    • 同意 BASH_REMATCH 真是个愚蠢的名字。简单的 GROUPMATCH 就足够了。
    【解决方案4】:

    使用为此类转换优化的date

    $ str="20140613"
    $ date +"%m%d%Y" -d "$str"
    06132014
    

    当你必须转换日期时,不需要看这么远;)

    【讨论】:

    • 确实如此。对于特定日期的转换,日期通常是正确的工具。
    【解决方案5】:

    使用 sed:

    STRING="20140613"
    STRING=$(echo $STRING | sed 's/\(....\)\(.*\)/\2\1/')
    

    【讨论】:

      【解决方案6】:

      或者使用awk:

      echo 20140613 | awk '{print substr($0,5,7) substr($0,1,4)}'
      

      测试:

      ~$ echo 20140613 | awk '{print substr($0,5,7) substr($0,1,4)}'
      >> 06132014
      

      【讨论】:

        【解决方案7】:

        通过 sed,

        $ echo 20140613 | sed 's/^\(.\{4\}\)\(.\{4\}\)$/\2\1/g'
        06132014
        

        通过perl

        $ echo 20140613 | perl -pe 's/^(.{4})(.{4})$/\2\1/g'
        06132014
        

        【讨论】:

        • 您可以进一步改进 sed 命令为 sed -r "s/^(.{4})(.{4})/\2\1/"
        【解决方案8】:

        使用 GNU Coreutils:

        input=20140613
        output=$(echo $input | fold -w4 | tac | tr -d \\n)
        

        如果您还需要最后一个换行符,您可以将 tr -d \\n 替换为 printf %s%s\\n 或将 && echo 附加到命令中。

        【讨论】:

          【解决方案9】:

          使用 perl

          for str in 11112222 1111xxxx2222 111222
          do
              echo -n "$str -> "
              echo "$str" | perl -ple 's/^(.{4})(.*)(.{4})$/\3\2\1/'
          done
          

          产生:

          11112222 -> 22221111
          1111xxxx2222 -> 2222xxxx1111
          111222 -> 111222
          

          【讨论】:

          • 这种任务可以用sed来完成。使用像 perl 这样的完整技术在 shell 脚本中制作偶尔的小东西并不是很实用。
          • @IdrissNeumann OMG 为什么?特别是对于偶尔的小任务,不管你用什么,重要的是完成任务。我多次使用sed,但这里已经有一些sed asnwers,所以添加了一个perl。奇怪的是,在您的(好)答案中,您使用的是date 而不是sed。 :) 也许您应该定义什么是“小而偶然”以及什么任务是“大而常见”。 :) 你能告诉我,为什么 small and occasional 任务使用 perl 是“不实用的”? :)
          • @jm666 我更喜欢使用date,这是针对这种特殊情况进行日期转换的正确外壳工具。但是,总的来说,我认为引入像 Perl(或 Python,或 PHP-cli 以同样的方式)这样的技术来在 shell 脚本中进行类似的小操作并不实用。在我看来,最好在 bash 脚本中使用sedawkgrep、bash 内建命令、date 等其他命令。
          • @IdrissNeumann 这是一个普遍的误解,perl 仅适用于 Web 开发或一些非常难以使用其他工具完成的任务。这不是真的。 Perl 完美地适用于 bash scipts 和/或作为单行代码。 ;) 尽管如此,你只是重复了你已经说过的话,没有任何解释 - 好的 - 我接受你的观点。 ;)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-12-20
          • 2021-01-04
          • 2011-03-25
          • 1970-01-01
          • 2022-01-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多