【问题标题】:How to swap only numeric values in each line如何仅交换每行中的数值
【发布时间】:2019-09-12 02:43:50
【问题描述】:

我只需要使用 sed 在特定字符串“PIC”之后交换每一行中的数值。 例如:

hello PIC A(12), and this PIC B(11)

想要的输出是:

hello PIC B(11), and this PIC A(12)

字符“B”和“A”在其他行中可能不同,但字符串 PIC 始终存在。

我正在尝试使用 sed 命令:

echo "hello PIC A(12), and this PIC B(11)" | sed '/PIC X(12)/s/PIC X(12)/PIC X(11)/g'

但似乎无法正常工作。

感谢所有回复。

【问题讨论】:

  • 12 是固定值吗?如果没有,请尝试sed -E 's/(PIC )([A-Z]\([0-9]+\))(.*PIC )([A-Z]\([0-9]+\))/\1\4\3\2/'
  • 太棒了!这是工作!所以,在文件中有很多行,长度不同,但总是有 PIC A() 值,所以你的代码似乎改变了一切。 !谢谢@WiktorStribiżew !!!
  • 我可以知道您使用 sed 命令在哪里学到的吗?我面临很多需要使用此工具的情况。谢谢@WiktorStribiżew
  • 我已经使用 Linux 快两年了,我几乎所有的sed 知识都来自 SO 和相关网站。按照标签,尝试回答问题,即使您不发布它们也会学到很多东西。在sed 不够或者太麻烦的地方,我改用 Perl。 awk 已被证明是一个不错的选择,当字符串可以被视为一些分隔符分隔的字符串时。
  • @Sunny,fwiw,我刚刚写了一个 sed 教程和参考 here。欢迎您的反馈!

标签: linux bash sed scripting


【解决方案1】:

您可以直接使用substitute 命令,因为它只会更改找到匹配项的行。

使用这个 POSIX ERE

sed -E 's/(PIC )([A-Z]\([0-9]+\))(.*PIC )([A-Z]\([0-9]+\))/\1\4\3\2/'

或者,POSIX BRE

sed 's/\(PIC \)\([A-Z]([0-9]*)\)\(.*PIC \)\([A-Z]([0-9]*)\)/\1\4\3\2/'

两个版本的括号转义不同:在 POSIX BRE 中,\(...\) 表示捕获组,() 是匹配文字括号,而在 POSIX ERE 中,反之亦然。

POSIX ERE 模式详情:

  • (PIC ) - 第 1 组:PIC 和空格
  • ([A-Z]\([0-9]+\)) - 第 2 组:任何大写 ASCII 字母,(,1+ 位,)
  • (.*PIC ) - 第 3 组:任意 0 个或多个字符、PIC、空格
  • ([A-Z]\([0-9]+\)) - 第 4 组:一个大写字母,(,1+ 个数字,)

【讨论】:

    【解决方案2】:

    如果 'd' 文件中有数据,请在 gnu sed 上尝试

    sed -E 's/(hello PIC )(\w+)(\S+, and this PIC )(\w+)/\1\4\3\2/' d
    

    【讨论】:

    • 从未使用过 .d 文件,但我相信我将来会使用它。感谢您的回复!
    • d 只是(诚然神秘!)输入文件的名称,它不是扩展名或任何有趣的东西。它可能被命名为 filefoo 或其他任何名称 - 它只是一个普通的旧文本文件。
    • 哦,明白了!谢谢@EdMorton!
    【解决方案3】:

    使用任何 POSIX sed:

    $ sed 's/\(PIC [[:upper:]]([0-9]*)\)\(.*\)\(PIC [[:upper:]]([0-9]*)\)/\3\2\1/' file
    hello PIC B(11), and this PIC A(12)
    

    如果您没有 POSIX sed(例如 Solaris 上的旧 sed),则设置 LC_ALL=C 并将 [:upper:] 更改为 [A-Z]

    【讨论】:

    • 也谢谢你! :)
    • 嘿 Ed,我试图用你发布的相同命令来移动三个单词,但它没有帮助.. 我试图移动:如果例如:OCCURS ## TIMES PIC ##( ##) 并且需要制作 PIC ##(##) OCCURS ## TIMES .. 数字而不是哈希 .. 当您调用字符串时,我试图理解序列。我试过`` sed -E 's/(OCCURS[0-9]+)(TIMES+)(PIC[0-9]([0-9]+))/\3\1\2/' ``
    • @Sunny 你为什么不使用the answer you accepted?无论如何,用它自己的minimal reproducible example 发布一个新问题以获得帮助。
    • @Sunny 确实提出了一个新问题,但首先 - 你认为TIMES+ 在正则表达式中是什么意思?此外,您的字符串中似乎有空格(例如OCCURS ## TIMES),但在您的正则表达式(例如(OCCURS[0-9]+)(TIMES+))中没有与它们匹配的空格或元字符,所以这是它永远不会匹配字符串的原因之一。
    • 是的,我试图在提问之前从网站上找到匹配的问题,但还没有找到。是的,我在给你发送代码后得到了这个,所以我尝试了这个 `` sed -E 's/(OCCURS[0-9])(TIMES)(PIC[0-9]([0-9])) /\3\1\2/' ``,但效果不佳
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 2020-05-15
    • 1970-01-01
    相关资源
    最近更新 更多