我有这个测试文件.
[root@localhost ~]# cat f.txt "a aa" MM "bbb b" MM MM MM"b b " [root@localhost ~]#
我想替换引号中的所有空格字符,注意,仅在引号中.不应触及引号中的所有字符.也就是说,我想要的是类似于:
"a_aa" MM "bbb__b" MM MM MM"b_b_"
这可以用sed实现吗?
谢谢,
这是一个完全不平凡的问题.
这可以用下划线替换引号内的第一个空格:
$ sed 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' f.txt
"a_aa" MM "bbb_ b"
MM MM
MM"b_b "
$
Run Code Online (Sandbox Code Playgroud)
对于此示例,如果任何引号内部的空格不超过两个,则只需重复该命令即可,但结果不正确:
$ sed -e 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' \
> -e 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' f.txt
"a_aa"_ MM "bbb_ b"
MM MM
MM"b_b_"
$
Run Code Online (Sandbox Code Playgroud)
如果你的sed支持版本的扩展正则表达式',那么这适用于示例数据:
$ sed -E \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> f.txt
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
$
Run Code Online (Sandbox Code Playgroud)
你必须为双引号内的每个空间重复那个可怕的正则表达式 - 因此对于第一行数据是三次.
正则表达式可以解释为:
由于启动锚,每个空白必须重复一次......但是sed有一个循环结构,所以我们可以这样做:
$ sed -E -e ':redo
> s/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/
> t redo' f.txt
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
$
Run Code Online (Sandbox Code Playgroud)
所述:redo定义的标签; 该s///命令是如前; t redo如果自上次读取行或跳转到标签以来已完成任何替换,则命令跳转到标签.
鉴于评论中的讨论,有几点值得一提:
该-E选项适用sed于MacOS X(已测试10.7.2).GNU版本的相应选项sed是-r(或--regex-extended).该-E选项与grep -E(也使用扩展正则表达式)一致."经典Unix系统"不支持ERE sed(Solaris 10,AIX 6,HP-UX 11).
您可以替换?我使用的(这是强制使用ERE而不是BRE的唯一字符)*,然后处理括号(在BRE中需要使用反斜杠以使它们成为捕获括号) ,离开剧本:
sed -e ':redo
s/^\(\([^"]*\("[^ "]*"\)*\)*\)\("[^ "]*\) \([^"]*"\)/\1\4_\5/g
t redo' f.txt
Run Code Online (Sandbox Code Playgroud)
这在同一输入上产生相同的输出 - 我在输入中尝试了一些稍微复杂的模式:
"a aa" MM "bbb b"
MM MM
MM"b b "
"c c""d d""e e" X " f "" g "
"C C" "D D" "E E" x " F " " G "
Run Code Online (Sandbox Code Playgroud)
这给出了输出:
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
"c_c""d_d""e__e" X "_f_""_g_"
"C_C" "D_D" "E__E" x "_F_" "_G_"
Run Code Online (Sandbox Code Playgroud)即使使用BRE表示法,也sed支持使用\{0,1\}符号指定前一个RE术语的0或1次出现,因此?可以使用以下方法将版本转换为BRE:
sed -e ':redo
s/^\(\([^"]*\("[^ "]*"\)\{0,1\}\)*\)\("[^ "]*\) \([^"]*"\)/\1\4_\5/g
t redo' f.txt
Run Code Online (Sandbox Code Playgroud)
这产生与其他替代品相同的输出.