从双引号bash脚本中包含的字符串中删除空格

时间:2012-05-23 23:21:47

标签: string bash unix awk

我一直在使用sep来尝试这个,基本上我有一个文本文件,其中包含相同数量的相同行,例如。

4444 username "some information" "someotherinformation" "even more information"

我需要用下划线替换引号内的空格,使它看起来像这样

4444 username "some_information" "someotherinformation" "even_more_information"

目前我已经能够分开引用的信息

sed 's/"\([^"]*\)"/_/g' myfile.txt

关于如何进行的建议?

4 个答案:

答案 0 :(得分:6)

sed -r ':a; s/^((([^"]*"){2})*[^"]*"[^" ]*) /\1_/;ta'
4444 username "some_information" "someotherinformation" "even_more_information"

sed ':a; s/^\(\(\([^"]*"\)\{2\}\)*[^"]*"[^" ]*\) /\1_/;ta'
4444 username "some_information" "someotherinformation" "even_more_information"
  • :a - 为循环标记“a”
  • s/// - 执行替换
  • ^( - 将整个搜索字符串锚定在该行的开头
  • (([^"]*"){2})* - 捕获(在第1组中)两组零个或多个非引号,后跟一个引号(零次或多次)
  • [^"]*" - 后跟零或多个非引号,后跟引号
  • [^" ]* - 后跟零个或多个不是空格或引号的字符
  • ) - 结束锚定序列并寻找替换所需的空间
  • \1 - 替换匹配序列的捕获组和下划线
  • ta - 如果已成功完成替换,则将分支(转移执行)标记为:a(如果没有,则继续执行下一条指令 - 在这种情况下,将结束此行的处理,阅读下一篇,开始新一轮处理)

这将找到最后一个带引号的字符串中的第一个空格,该空格具有任意空格并替换它。然后是下一个,如果有的话,直到引用的字符串结束。等等任何额外的空间。

然后是包含空格的下一个前一个带引号的字符串......依此类推。

这是:a ... ta循环每一步的模式空间:

4444 username "some information" "someotherinformation" "even_more information"

4444 username "some information" "someotherinformation" "even_more_information"

4444 username "some_information" "someotherinformation" "even_more_information"

然后它会再次进行几次寻找行开头的任何匹配。

答案 1 :(得分:3)

EDITED

以前的版本会添加不需要的空格。这个版本完全符合OP的要求。

这可能是获得你想要的最简单方法。

awk -F'"' '
  BEGIN {
    OFS="\""
  }
  {
    for (i = 2; i < NF; i += 2) {
      gsub(/[ \t]+/, "_", $i)
    }

    print $0
  }
' file > outputFile

答案 2 :(得分:0)

我实际上是在C中执行此操作,这使得比大多数高级语言更容易执行逐个字符的状态机。

#include <stdio.h>
int main(void)
{
    int inside_quotes = 0;
    int backslash = 0;
    int c;
    while ((c = getchar()) != EOF) {
        switch (c) {
        case ' ':
            if (inside_quotes)
                c = '_';
            break;
        case '"':
            if (!backslash)
                inside_quotes = !inside_quotes;
            break;
        case '\\':
            if (!backslash)
                backslash = 2;
            break;
        default:
            break;
        }
        if (backslash > 0) backslash--;
        putchar(c);
    }
    return 0;
}

未测试甚至未编译。特别是反斜杠处理很可能是错误的。

答案 3 :(得分:0)

这可能对您有用:

echo '4444 username "some information" "someotherinformation" "even more information"' |
sed 's/"[^"]*"/\n&/g;:a;s/\(\n"[^"]*\) /\1_/g;ta;s/\n//g'
4444 username "some_information" "someotherinformation" "even_more_information"
  • 为引用的字符串添加标记(\n)。 sed 's/"[^"]*"/\n&/g;
  • 将引用字符串中的所有空格替换为_:a;s/\(\n"[^"]*\) /\1_/g;ta
  • 删除标记。 s/\n//g