我一直在为脚本而苦苦挣扎。 我有一份体操队和分数的名单。 我已经设法将文件管道分隔开来,就像下面的小数据示例一样。 但是,现在我需要用空格替换管道,但前提是它在字母单词之间。 数字之间的管道必须保留。 这样,我可以将团队名称作为一个字段,无论组成多少个单词。 然后,数据将准备好加载到我的数据库中。 我知道sed
或awk
使用正则表达式应该能够做到这一点,但我还没有弄清楚。 我一整天都在搞砸这个,我相信有人可能会在 2 分钟内告诉我如何做到这一点。:-)
起始格式:
Twistars|28.250|28.700|28.100|27.950|113.600
Excel|Gymnastics|28.250|28.700|28.100|27.950|113.600
Head|Over|Heels|Gymnastics|28.250|28.700|28.100|27.950|113.600
我的最终目标:
Twistars|28.250|28.700|28.100|27.950|113.600
Excel Gymnastics|28.250|28.700|28.100|27.950|113.600
Head Over Heels Gymnastics|28.250|28.700|28.100|27.950|113.600
任何建议/小例子将不胜感激。
这是一个awk
的解决方案:
awk -F| '{printf $1;for (i=2;i<=NF;i++) printf (($(i-1)!~/[0-9.]+/ && $(i)!~/[0-9.]+/)?" ":"|")"%s",$i;print ""}' file
Twistars|28.250|28.700|28.100|27.950|113.600
Excel Gymnastics|28.250|28.700|28.100|27.950|113.600
Head Over Heels Gymnastics|28.250|28.700|28.100|27.950|113.600
这可能对你有用(GNU sed):
sed -r ':a;s/([[:alpha:]])|([[:alpha:]])/1 2/g;ta' file
这会用空格替换单词之间的|
。第二次扫荡会抓住第一次传球时错过的任何比赛。
with sed
sed 's/([[:alpha:]])|([[:alpha:]])/1 2/g' file
Twistars|28.250|28.700|28.100|27.950|113.600
Excel Gymnastics|28.250|28.700|28.100|27.950|113.600
Head Over Heels Gymnastics|28.250|28.700|28.100|27.950|113.600
假设最后 5 个字段不应连接:
awk '{p=$0; for(i=1;i<=NF-6;i++) sub(FS,OFS,p); print p}' FS='\|' file
echo 'Excel|Gymnastics|28.250|28.700|28.100|27.950|113.600' | sed 's/([A-Za-z])|([A-Za-z])/1 2/g'
以上输出
Excel Gymnastics|28.250|28.700|28.100|27.950|113.600
上面显示了您需要的基本sed
表达式。您可以通过几种不同的方式进行修饰。
cat file | sed 's/([A-Za-z])|([A-Za-z])/1 2/g' > newFile
sed 's/([A-Za-z])|([A-Za-z])/1 2/g' file > newfile
您甚至可以对某些版本的sed
使用"就地编辑"标志 - 这意味着您将在同一位置将文件写回原处:
sed -i 's/([A-Za-z])|([A-Za-z])/1 2/g' file
解释:
([A-Za-z]) capturing group: any character A-Z or a-z
| escaped pipe symbol (otherwise it means "or")
([A-Za-z]) second capturing group: any character A-Z or a-z
我们将上述内容替换为
1 2 first captured group, space, second captured group
/g global flag: do it for all occurrences
sed -e 's/([[:alpha:]])|([[:alpha:]])/1 2/g'
效果很好,除了单个字母会导致问题的事实:
$ echo 'Tete|A|Tete|4.489' | sed -e 's/([[:alpha:]])|([[:alpha:]])/1 2/g'
Tete A|Tete|4.489
这使得awk可能是一个更好的解决方案,尽管它更冗长。
由于您已经有一个文件,因此可以使用 ex:
printf '%%s/\([[:alpha:]]\)|\([[:alpha:]]\)/\1 \2/gn%%&gn%%pn' | ex -s file >file2
假设您使用的是支持 here-Documents 的 shell,您可以使其更具可读性,如下所示:
ex -s file >file2 <<EOF
%s/([[:alpha:]])|([[:alpha:]])/1 2/g
%&g
%p
EOF
它只是执行与sed相同的替换,只是它允许您使用&命令重复它。如果希望它只是就地修改文件,请删除>file2
并将%p
更改为w
:
ex -s file <<EOF
%s/([[:alpha:]])|([[:alpha:]])/1 2/g
%&g
w
EOF
应该有"一个 sed for ex",它使 ex 的功能可用于管道输入,就像 sed 对 ed 所做的那样,但我知道目前没有这样的实现。Emacs 附带了一个手册页,表明存在这样的实用程序,但该命令不可用,并且根本不会根据手册页执行 ex 所做的事情。