【问题标题】:insert a string at specific position in a file by SED awk通过 SED awk 在文件中的特定位置插入字符串
【发布时间】:2012-05-17 13:26:16
【问题描述】:

我有一个字符串需要插入到文件的特定位置:

该文件包含多个分号(;)我需要在最后一个“;”之前插入字符串

SED 可以做到这一点吗?

由于我是 shell 脚本的新手,请务必使用命令发布解释

之前:

adad;sfs;sdfsf;fsdfs

字符串 = jjjjj

之后

adad;sfs;sdfsf jjjjj;fsdfs

提前致谢

【问题讨论】:

  • 是的,这是可能的。请在替换前后使用您的文件的简短示例编辑帖子。

标签: shell sed awk tr


【解决方案1】:

这可能对你有用:

echo 'adad;sfs;sdfsf;fsdfs'| sed 's/\(.*\);/\1 jjjjj;/'
adad;sfs;sdfsf jjjjj;fsdfs

\(.*\) 贪婪并吞下整行,; 使正则表达式回溯到最后一个 ;\(.*\) 是一个反向引用 \1。将所有内容放在s 命令的RHS 中意味着在最后一个; 之前插入jjjjj

【讨论】:

  • 请注意,这将在包含至少一个分号的任何行中的最后一个分号之前插入字符串。这不完全是问题中指定的 file 的最后一个分号之前的 insertig。
  • @sg-lecram 如果插入是最后一个 ; 使用:sed ':a;$!{N;ba}; s/\(.*\);/\1 jjjjj;/' file
  • @potong:我不是sed 专家。这会将整个文件读入内存(通过使用N 命令)还是仍然适用于大文件?如果有的话,您至少可以删除倒数第二个分号之前的所有内容。这并不重要,我只是出于好奇而要求更多地了解sed 的力量。 :-)
  • @sg-lecram 是的。更有效的解决方案是将保持空间用作开关: sed '/;/{x;/;/p;x;h;$ba;d};x;/;/!{x;b};x ;H;$ba;d;:a;x;s/(.*);/\1 jjjjj;/' 文件。但是,如果 ; 仅出现在大文件的开头,则节省的费用将很少。
  • @potong:我预计节省的费用将取决于;s 分发。我喜欢你的代码,我期待着深入研究它。 :-)
【解决方案2】:
sed 's/\([^;]*\)\(;[^;]*;$\)/\1jjjjj\2/' filename

(用您需要插入的内容替换 jjjjj)。

例子:

$ echo 'adad;sfs;sdfsf;fsdfs;' | sed 's/\([^;]*\)\(;[^;]*;$\)/\1jjjjj\2/'
adad;sfs;sdfsfjjjjj;fsdfs;

解释:

sed 找到以下模式:\([^;]*\)\(;[^;]*;$\)。转义的圆括号(\(\))形成编号组,因此我们稍后可以将它们称为\1\2

[^;]* 是“除了; 之外的所有内容,重复任意次数。

$ 表示行尾。

然后将其更改为\1jjjjj\2

\1\2 是在第一和第二圆括号中匹配的组。

【讨论】:

  • 其实sputnick's answer更好。越简单越好 :) 工作方式相同。
  • 我进一步缩短了所说的答案。
【解决方案3】:

目前,使用sed 的较短解决方案:=)

sed -r 's@;([^;]+);$@; jjjjj;\1@' <<< 'adad;sfs;sdfsf;fsdfs;'
  • -r 选项代表扩展正则表达式
  • @是分隔符,已知的/分隔符可以替换为任何其他字符
  • 我们将不是 ; 的任何内容与最后一个 ; 匹配,$ 表示行尾
  • 我解释的最后一部分是用()捕获的
  • 最后,我们通过添加“; jjjj”替换匹配部分并将其与捕获的部分连接

编辑:POSIX 版本(更便携):

echo 'adad;sfs;sdfsf;fsdfs;' | sed 's@;\([^;]\+\);$@; jjjjj;\1@'

【讨论】:

  • 请注意,-r 是一个非标准的 GNU sed 选项。最好选择 POSIX sed 解决方案,在这种情况下很容易做到。
  • 好的,POSIX 解决方案已添加到我的 POST 中
  • 发帖者删除了“;”在他的样本输入的 EOL。
  • 您可以使用&amp; 操作符缩短它(引用整个匹配):sed 's@;[^;]*$@; jjjjj&amp;' &lt;&lt;&lt; 'adad;sfs;sdfsf;fsdfs'。这也符合 POSIX,因为您不再需要分组。
【解决方案4】:
echo 'adad;sfs;sdfsf;fsdfs;' | sed -r 's/(.*);(.*);/\1 jjjj;\2;/'

你不需要否定 ;因为 sed 在默认情况下是贪婪的,并且会选择尽可能多的字符。

【讨论】:

    【解决方案5】:
    sed -e 's/\(;[^;]*\)$/ jjjj\1/'
    

    $ 行的末尾处,在分号后跟任意数量的非分号 ([^;]*) 的部分之前插入 jjjj。 \1 称为反向引用,包含在\(\) 之间匹配的字符。

    更新:因为示例输入不再有“;”最后。

    【讨论】:

    • 请注意,&amp; 是对整个匹配项的反向引用:sed 's/;[^;]*$/ jjjjj&amp;/'
    【解决方案6】:

    这样的事情可能对你有用:

    echo "adad;sfs;sdfsf;fsdfs"| awk 'BEGIN{FS=OFS=";"} {$(NF-1)=$(NF-1) " jjjjj"; print}'
    

    输出:

    adad;sfs;sdfsf jjjjj;fsdfs
    

    说明: awk 以将 FS(字段分隔符)和 OFS(输出字段分隔符)设置为分号 ; 开头。 awk 中的NF 代表number of fields$(NF-1) 因此表示 last-1 字段。在这个 awk 命令 {$(NF-1)=$(NF-1) " jjjjj" 中,我只是将 jjjjj 附加到 last-1 字段。

    【讨论】:

    • @Jens 现在检查编辑后的答案。请记住,我在 OP 添加的示例之前提供了我的答案。我的编辑是对原始答案的小更新。
    • @user1271244:已添加说明,请检查。
    猜你喜欢
    • 2017-01-16
    • 2021-06-19
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多