Sed 在一组特定位置替换

Sed 在一组特定位置替换

我有一个示例输入文件,如下所示:

Apple   Orange      Gold    Silver Spoon Apple  Orange              Gold    
Apple          
Apple   Orange 
Apple   Orange      
Mango               Gold    Silver Spoon Apple  Orange  

我需要检查第 15 到 20 个位置是否为 Space ,然后将其替换为 string Silver。另外我需要将第 50 到 70 位置的内容完全替换为xxxxxxxxxxxxxxxxxxxxx

答案1

根据如何处理较小的行(请参阅上面我的评论),这里有一个sed解决方案:

sed -e '/^.\{14\} \{6\}/s/^\(.\{14\}\) \{6\}/\1Silver/' \
    -e '/^.\{49\}./s/^\(.\{49\}\)\(.\{1,21\}\)\?\(.*\)\?/\1xxxxxxxxxxxxxxxxxxxxx\3/'

以及一个更清晰(且不易出错)的 GNUawk版本:

awk '
  BEGIN { FIELDWIDTHS = "14 6 29 21 999" ; OFS = "" }
  $2 == "      " { $2 = "Silver" }
  $4 != ""       { $4 = "xxxxxxxxxxxxxxxxxxxxx" }
  { print }
'

解释:

1.) sed:sed命令由两个独立的替换构建,第一个处理“Silver”情况,第二个处理“xxx...”情况。替换的形式sed如下:

/pattern/s/pattern2/replacement/

如果第一个模式匹配,则执行相应的替换,并且对于这些行,第二个模式将被替换表达式替换。细节是sed典型的隐晦表达:

.- 任意字符

\{14\}- 重复前面的子表达式(此处 14 次)

\(expr\)- 可以在替换字符串中通过\1\2等引用的子表达式,其中实际数字由第 n 个括号表达式定义

\?- 指定前面的子表达式是可选部分

2.) awk:程序awk运行该部分一次,并仅在相应的左侧条件为真时运行BEGIN数据文件每一行的后续部分以及相应的右侧操作。{...}

FIELDWIDTHS- 指定输入行中数据字段的宽度,以便每个字段都可以通过$i(对于某些字段号 i )进行寻址

OFS=""- 空字符串;输出字段不应有任何额外的分隔

$2 == " "- 如果第二个字段(根据规范FIELDWIDTHS)包含六个空格,则将其替换为给定的字符串

$4 != ""- 如果第四个字段包含数据,请将其替换为“xxx...”字符串

{ print }- 当前行的无条件打印,该行要么被前面的一个或两个操作修改,要么显示未修改的行

答案2

sed 's/^\(.\{14\}\)      /\1Silver/
     s/^\(.\{49\}\).\{20\}/\1xxxxxxxxxxxxxxxxxxxxx/
'    <infile >outfile

是吗,我想。

答案3

假设应丢弃包含少于 21 个字符的行(对于第一次替换)和包含少于 70 个字符的行(对于第二次替换),使用 Perl:

< inputfile perl -pe 's/^(.{14}) {6}/$1Silver/; s/^(.{49}).{21}/$1xxxxxxxxxxxxxxxxxxxxx/' > outputfile

假设包含少于 21 个字符的行(对于第一次替换)和包含少于 70 个字符的行(对于第二次替换)应首先用空格填充,使用awk+Perl:

< inputfile awk '{printf "%-70s\n", $0}' | perl -pe 's/^(.{14}) {6}/$1Silver/; s/^(.{49}).{21}/$1xxxxxxxxxxxxxxxxxxxxx/' > outputfile

命令 #1 故障:

  • < inputfile: 将内容重定向inputfileperl'sstdin
  • -p: 强制 Perl 打印这些行
  • -e:强制 Perl 从参数中读取一行程序
  • > outputfileperl:将 的内容重定向stdoutoutputfile

命令#2 细分:

  • < inputfilein awk: 将内容重定向inputfileawk'sstdin
  • {printf "%-70s", $0}:用空格填充每行,直到该行的字符数为 70
  • |:awk管道stdoutperlstdin
  • -p: 强制 Perl 打印这些行
  • -e:强制 Perl 从参数中读取一行程序
  • > outputfileperl:将 的内容重定向stdoutoutputfile

替补#1 故障:

  • s:断言执行替换
  • /:开始搜索模式
  • ^: 匹配行的开头
  • (: 启动捕获组
  • .{14}: 匹配任意字符出现 14 次
  • ):停止捕获组
  • {6}: 匹配某个字符出现 6 次
  • /:停止搜索模式/开始替换模式
  • $1: 替换为捕获的组
  • Silver: 添加一个Silver字符串
  • /:停止替换模式

替补#2 细目:

  • s:断言执行替换
  • /:开始搜索模式
  • ^: 匹配行的开头
  • (: 启动捕获组
  • .{49}:匹配 49 次出现的任意字符
  • ):停止捕获组
  • .{21}: 匹配任意字符出现 21 次
  • /:停止搜索模式/开始替换模式
  • $1: 替换为捕获的组
  • xxxxxxxxxxxxxxxxxxxxx: 添加一个xxxxxxxxxxxxxxxxxxxxx字符串
  • /:停止替换模式

示例输出:

:~/tmp$ cat inputfile
Apple   Orange      Gold    Silver Spoon Apple  Orange              Gold    
Apple          
Apple   Orange 
Apple   Orange      
Mango               Gold    Silver Spoon Apple  Orange  
~/tmp$ < inputfile perl -pe 's/^(.{14}) {6}/$1Silver/; s/^(.{49}).{21}/$1xxxxxxxxxxxxxxxxxxxxx/'
Apple   OrangeSilverGold    Silver Spoon Apple  Oxxxxxxxxxxxxxxxxxxxxxld    
Apple          
Apple   Orange 
Apple   OrangeSilver
Mango         SilverGold    Silver Spoon Apple  Orange  
~/tmp$ < inputfile awk '{printf "%-70s\n", $0}' | perl -pe 's/^(.{14}) {6}/$1Silver/; s/^(.{49}).{21}/$1xxxxxxxxxxxxxxxxxxxxx/'
Apple   OrangeSilverGold    Silver Spoon Apple  Oxxxxxxxxxxxxxxxxxxxxxld    
Apple         Silver                             xxxxxxxxxxxxxxxxxxxxx
Apple   OrangeSilver                             xxxxxxxxxxxxxxxxxxxxx
Apple   OrangeSilver                             xxxxxxxxxxxxxxxxxxxxx
Mango         SilverGold    Silver Spoon Apple  Oxxxxxxxxxxxxxxxxxxxxx
~/tmp$

相关内容