我有一个示例输入文件,如下所示:
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
: 将内容重定向inputfile
到perl
'sstdin
-p
: 强制 Perl 打印这些行-e
:强制 Perl 从参数中读取一行程序> outputfile
perl
:将 的内容重定向stdout
到outputfile
命令#2 细分:
< inputfile
inawk
: 将内容重定向inputfile
到awk
'sstdin
{printf "%-70s", $0}
:用空格填充每行,直到该行的字符数为 70|
:awk
管道stdout
到perl
的stdin
-p
: 强制 Perl 打印这些行-e
:强制 Perl 从参数中读取一行程序> outputfile
perl
:将 的内容重定向stdout
到outputfile
替补#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$