【问题标题】:Passing part of patterns from sed to shell将部分模式从 sed 传递到 shell
【发布时间】:2012-02-21 15:25:31
【问题描述】:

我有一个文件,其中包含以下格式的行:

w1#1#x w2#4#b w3#2#d ...

行中的每个单词(标记)(例如 w1#1#x)由 3 个部分组成,第一个显示一些索引(在这种情况下为 w1),第二个是一个整数(在这种情况下为 1),并且第三个是字符(本例中为 x)

现在,对于每个单词(令牌),我需要打印一个附加字段,该字段将根据第二部分和第三部分的值计算(ie,第四部分将是第二部分的函数和第 3 部分),输出文件应如下所示:

w1#1#x#f1 w2#4#b#f2 w3#2#d#f3 ...

在哪里

f1 = 函数(1,x), f2 = 函数(4,b), f3 = 函数(2,d)

现在,使用 sed 模式,我可以识别每个单词(标记)中的组件,例如,

回显 $line | sed "s/([^#])#([^#])#([^#]*) /\1#\2#\3 /g"

其中 \2 和 \3 是 模式的一部分(我称它们为 模式的一部分,因为 this link

现在,我需要使用 \2 和 \3 计算第四部分。我已经定义了一个 shell 函数 getInfo(),它接受 2 个参数并进行所需的计算并将第四部分返回给我。问题是在 sed 命令中插入此函数。我尝试了以下操作:

回显 $line | sed "s/([^#])#([^#])#([^#]*) /\1#\2#\3`getInfo \2 \3` /g "

但这不起作用。 Shell 没有接收模式的部分作为参数。

所以问题是:

如何将 sed 模式的部分传递给 shell(函数)?

我可以轻松编写一个 shell 脚本,它会逐字拆分行并完成所需的工作,然后将文件缝合回去,但如果 shell 可以接收 部分模式,我将不胜感激 em> 作为 sed 命令中 sed 的参数。

问候,

萨利尔·乔希

【问题讨论】:

    标签: shell sed


    【解决方案1】:

    这可能对你有用:

    func(){ echo "$1#$2#$3#$2$3"; }
    export -f func
    echo "w1#1#x w2#4#b w3#2#d" |
    sed 's/\([^#]*\)#\([^#]*\)#\([^ ]*\) \?/echo -n "$(func \1 \2 \3) "; /g;s/$/echo ""/' |
    sh
    w1#1#x#1x w2#4#b#4b w3#2#d#2d 
    

    或者如果你有 GNU sed:

    func(){ echo "$1#$2#$3#$2$3"; }
    export -f func
    echo "w1#1#x w2#4#b w3#2#d" |
    sed 's/\([^#]*\)#\([^#]*\)#\([^ ]*\) \?/echo -n "$(func \1 \2 \3) "; /ge;s/.$//'
    w1#1#x#1x w2#4#b#4b w3#2#d#2d
    

    【讨论】:

    • +1 巧妙地演示了它可以通过 sed 完成,并且有足够的技巧。不过,这绝对是(IMO)超越了明智的极限。特别是,如果数据文件包含 shell 元字符,则执行 shell 函数可能很危险。如果数据只是带有简单空格和字母数字的多重哈希条目,那么您就可以了。
    • 令人印象深刻...就像@JonathanLeffler 提到的那样,尽管这可能不适用于所有情况,但我会保留它以供将来参考。非常感谢。
    • 达尔文用户请注意,我必须以这种方式更改 sed 语法(-E 开关,取消转义正则表达式指令):echo "w1#1#x w2#4#b w3#2#d" | sed -E 's/([^#]*)#([^#]*)#([^ ]*) ?/echo "$(func \1 \2 \3)";/g;s/$/echo ""/' | sh
    【解决方案2】:

    有一点,sed 不再是job 的正确工具。我认为这项任务已经达到了这一点(但请参阅potong 的聪明的answer,这表明它可以通过bashsed 完成)。

    您使用哪种替代工具?您没有显示该函数,但如果可以在 shell 中使用 shell 函数方便地计算它,那么awk 的功能可能足以完成这项工作。我自己可能会求助于 Perl,但 Python(或 Ruby)也可以很好地工作。所有这些都允许您编写一个函数,读取数据并将该函数应用于数据,然后再将数据写回。

    尝试使用sed中的函数的问题在于它没有定义函数或执行shell函数的机制。要使用sed,您必须考虑两次遍历数据,第一次提取(唯一)标记以进行后续处理,这会将 shell 函数应用于每个标记,生成 一个 sed 脚本,它简单地匹配每个令牌并用它的替换替换它,然后在第二次传递数据时应用该脚本。

    【讨论】:

    • 感谢乔纳森的建议。就像我提到的,我可以编写这些函数(甚至在 Python、Ruby 等中),但是很长一段时间,我想知道 sed 是否可以将这些部分导出回 shell。从您的回答来看,答案似乎是否定的 :-(
    • 正确 - 答案是(出于所有实际目的)否。如果在生死攸关的情况下无法使用 Perl、Awk、Python,那么可以采用多步骤方案使用seduniqsort、你的shell函数等设计的。但除非对可用的工具集有愚蠢的限制,否则sed这次不是正确的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-09
    • 1970-01-01
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    相关资源
    最近更新 更多