Regex 如果该行没有';不能使用sed包含另一个字符串

Regex 如果该行没有';不能使用sed包含另一个字符串,regex,bash,sed,Regex,Bash,Sed,我在linux服务器上合并了许多文本文件,但其中一些行略有不同,我需要统一它们 例如,某些文件将具有类似于 id='1244' group='american' name='fred',american 其他文件将类似于 id='2345' name='frank', english id='7897' group='' name='maria',scottish 最后其他人也会这样 id='2345' name='frank', english id='7897' group='' n

我在linux服务器上合并了许多文本文件,但其中一些行略有不同,我需要统一它们

例如,某些文件将具有类似于

id='1244' group='american' name='fred',american
其他文件将类似于

id='2345' name='frank', english
id='7897' group='' name='maria',scottish
最后其他人也会这样

id='2345' name='frank', english
id='7897' group='' name='maria',scottish
我需要做的是,如果group=''或group根本不在字符串中,我需要将其添加到逗号之前的某个位置,将其设置为逗号之后的文本,因此在第二个示例中,该行上方将变为:

id='2345' name='frank' group='english',english
在最后一个例子中也是一样的

id='7897' name='maria' group='scottish',scottish
这将进入bash脚本。实际上,我不能删除该行并将其添加到文件末尾,因为它与下一行相关

我使用了以下方法:

sed -i.bak 's#group=""##' file 
sed -i.bak '/group/! s#,(.*$)#group="\1",\1#' file
这将删除group=”“字符串,因此行将包含group='something'或根本不包含它,这样就可以了

然后,我尝试使用以下方法添加不存在的组:

sed -i.bak 's#group=""##' file 
sed -i.bak '/group/! s#,(.*$)#group="\1",\1#' file
但这就产生了错误

sed: -e expression #1, char 38: invalid reference \1 on `s' command's RHS
编辑Ed Morton编写的以创建单个示例输入文件和预期输出:

样本输入:

id='1244' group='american' name='fred',american
foo
id='2345' name='frank', english
bar
id='7897' group='' name='maria',scottish
预期产出:

id='1244' group='american' name='fred',american
foo
id='2345' name='frank' group='english',english
bar
id='7897' name='maria' group='scottish',scottish
差不多

sed  '
    /^[^,]*group[^,]*,/ ! {
        s/, *\(.*\)/ group='\''\1'\'', \1/
    }
    /^[^,]*group='\'\''/ {
        s/group='\'\''\([^,]*\), *\(.*\)/group='\''\2'\''\1, \2/
    }
'

此GNU
awk
可能有助于:

awk -v sq="'" '
  BEGIN{RS="[ ,\n]+"; FS="="; found=0}
  $1=="group"{
    if($2==sq sq) 
      {next}
    else
      {found=1}
  }
  NF>1{
    printf "%s=%s ",$1,$2
  }
  NF==1{
    if(!found)
      {printf "group=%s",$1}
    print ","$1
    found=0
  }
' file
脚本依赖于记录分隔符
RS
,该分隔符设置为获取所有
key='value'

如果未找到键
或键为空,则在到达只有一个字段的记录时将打印该键


请注意,变量
sq
包含单引号字符,用于检测空的
字段。

Sed可能非常难看。而且您的数据格式似乎有些不一致。这可能适合您:

$ sed -e "/group='[a-z]/b e" -e "s/group='' *//" -e "s/,\([a-z]*\)$/ group='\1', /" -e ':e' input.txt
为了便于阅读,我们正在做以下工作:

  • /group='[a-z]/be
    -如果行包含有效的
    ,则分支到末尾
  • s/group=''*/
    -删除任何空组
  • s/,\([a-z]*\)$/group='\1',/
    -根据您的规格添加一个新组
  • :e
    -第一个命令的分支标签
  • 然后默认操作是打印行
我真的不喜欢这样操纵数据。它很容易出错,您可以进一步将这些数据读入到准确存储其数据结构的内容中,然后根据新结构打印数据。一个更健壮的解决方案很可能直接与产生或消耗数据的任何东西联系在一起,而不会像这样坐在中间。
sed -r "
    /group=''/ s///                                   # group is empty, remove it
    /group=/!  s/,[[:blank:]]*(.+)/ group='\\1',\\1/  # group is missing, add it
" file

foo和bar行未被触及,因为s///命令与后跟字符的逗号不匹配。

到目前为止您尝试了什么?让我们看一些代码:-)抱歉,我编辑了我的问题以显示我的尝试。在BRE(基本正则表达式)语法中,sed的默认模式语法,捕获组的括号必须转义:
\(.*$\)
,否则,它们被视为文字字符。我编辑了您的问题,试图提供一个示例输入文件和给定该输入的预期输出。如果它是错误的,那么请修复它。一堆单独的输入行,一些有预期的输出,一些没有,并且没有一行有周围行的上下文,几乎没有上下文的一个具体示例有用。这为我指明了正确的方向,它似乎完全按照所描述的那样做,但EOL似乎把它搞砸了。我得到的输出像id='7897'name='maria'group='scottish,所以错过了小组的最后一个'和逗号之后的文本。我的最新版本可能是因为我已经在文件上使用了sed-I-e“s/^m//g”?#听起来像是停留回车
s/\r$/
使用回车符,我希望您会看到行尾覆盖行首:
,苏格兰名称='maria'group='scottish