使用awk或sed删除字符串中的空格

时间:2016-04-13 15:34:55

标签: bash awk sed

给定输入文件:

col1 as 'prod 1', col3 as 'prod 2', col9 as 'prod type 2'

需要删除引号并用_替换引号内的空格。我们可以用awk或sed来做吗?

期望的输出:

col1 as prod_1, col3 as prod_2, col9 as prod_type_2

5 个答案:

答案 0 :(得分:2)

简单易用的awk解决方案:

awk -v RS="'" -v ORS='' 'NR%2==0{gsub(" ","_")}1'

将记录分隔符设置为单引号,然后替换每个第二条记录中的空格(即单引号之间的空格)。

允许在单引号字符串中使用换行符,并且不会修改它们。如果要替换所有空格,可以更改gsub调用以使用简单的正则表达式:

awk -v RS="'" -v ORS='' 'NR%2==0{gsub(/[[:space:]]+/,"_")}1'

例如:

$ awk -v RS="'" -v ORS='' 'NR%2==0{gsub(/[[:space:]]+/,"_")}1' <<<"
> col1 as 'prod 1', col3 as 'prod
> 2', col9 as 'prod type 2'
> "
col1 as prod_1, col3 as prod_2, col9 as prod_type_2

答案 1 :(得分:1)

sed解决方案:

如果您可以假设引用的字符串没有前导空格,那么这样做:

sed ":a; s/\('[^,][^' \\t]*\)\s/\1_/; ta" my_file

如果您还需要在字符串中容纳前导空格,那么这样做:

sed -e "s/\s*$//" \
    -e ":a; s/\('[^,][^' \\t]*\)\s/\1_/; ta" \
    -e "s/' /'_/; ta" \
    my_file

后者还具有修剪拖尾空白的副作用;如果有必要,可以以更复杂的命令为代价来避免这种情况。

这两个假设字符串的结尾'与任何后续逗号(,)之间不会有空格。

这两个都必须处理sed的替换行为:即使g命令被赋予s选项,也不会考虑跳过或转贴一次的文本通过相同的s命令进一步匹配。这就产生了将字符串中的空白与外部空白区分开来的问题。这些sed命令通过使用标签(:a)和条件分支(ta来解决这个问题,其中t是命令,a是目标标签)无论何时进行替换,都要从头开始重新运行整个替换命令。

答案 2 :(得分:1)

使用GNU awk进行多字符RSRT\s

$ awk -v RS="'[^']+'" '{gsub(/\s/,"_",RT); ORS=RT}1' file
col1 as 'prod_1', col3 as 'prod_2', col9 as 'prod_type_2'

鉴于删除封闭引号的新要求:

$ awk -v RS="'[^']+'" '{gsub(/\s/,"_",RT); gsub(/\047/,"",RT); ORS=RT}1' file
col1 as prod_1, col3 as prod_2, col9 as prod_type_2

或者如果您愿意:

$ awk -v RS="'[^']+'" '{gsub(/\s/,"_",RT); ORS=substr(RT,2,length(RT)-2)}1' file
col1 as prod_1, col3 as prod_2, col9 as prod_type_2

答案 3 :(得分:0)

echo "col1 as 'prod 1', col3 as 'prod 2', col9 as 'prod type 2'" | \
awk -F"'" 'BEGIN{OFS=""}{for(i=2;i<NF;i+=2)gsub(" ","_",$i)}1'
col1 as prod_1, col3 as prod_2, col9 as prod_type_2

<强>解释

  • -F"'" f 字段分隔符设置为',将每个输入行拆分为字段'分隔$1="col1 as "$2="prod 1"$3=" col3 as ",...)
  • BEGIN{OFS=""}设置 o 输出 f ield s eparator 到空字符串,有效删除所有' s。
  • for(i=2;i<NF;i+=2)会在{strong> n f 之前对所有偶数进行迭代i ields
  • gsub(" ","_",$i)i替换字段 _中的所有空格。
  • 1只会打印(修改过的)行

编辑: 此方法的一个缺点(?)/功能是它按行分割,因此单引号部分不能跨越多行。如果这是一个问题,将'拆分为记录而不是字段将是解决方案(如rici&#39; s answer):

echo "col1 as 'prod 1', col3 as 'prod 2', col9 as 'prod type 2'" | \
awk -F\  -v RS="'" -v ORS='' -v OFS='_' '!(NR%2){$1=$1}1
col1 as prod_1, col3 as prod_2, col9 as prod_type_2

<强>解释

  • -v RS="'" r ecord s eparator 设置为'分割输入记录' s(而非行)分隔
  • -F\ f 字段分隔符设置为,拆分每个输入记录 into fields 分隔$1="col1 as "$2="prod 1"$3=" col3 as ",...)
  • -v ORS=''设置 o 输出 r ecord s eparator 到空字符串,有效删除所有' s
  • -v OFS='_'设置 o 输出 f ield s eparator _,在修改后的()行中有效地用_ s 替换空格
  • !(NR%2)相当于NR%2==0,并测试当前记录(由 n 标识 r ecords )是一个奇怪的(%是模运算符)
  • {$1=$1}自行分配第一个字段,标记当前记录已修改(即使它实际上没有改变),有效地替换所有奇数记录中的_个空格({em>即<{1}}之间的文本
  • '只会打印每个记录

答案 4 :(得分:0)

使用gnu-awk:

str="col1 as 'prod 1', col3 as 'prod 2', col9 as 'prod type 2'"

awk -v sq="'" -v re="'[^']*'" -v FPAT="'[^']*'|[^']*" '{
   for(i=1; i<=NF; i++) if ($i ~ re) {
      gsub(/[[:blank:]]/, "_", $i);
      gsub(sq, "", $i)
   }
} 1' OFS= <<< "$str"

<强>输出:

col1 as prod_1, col3 as prod_2, col9 as prod_type_2