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

3
我一直在使用sep尝试这个,基本上我有一个文本文件,其中包含相同的行,例如:
4444 username "some information" "someotherinformation" "even more information"

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

4444 username "some_information" "someotherinformation" "even_more_information"

目前我已经能够分离引用的信息。
sed 's/"\([^"]*\)"/_/g' myfile.txt

如何继续?建议?

你的字段之间的空格有多重要? - lxop
4个回答

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 - 用捕获的组和下划线替换匹配到的序列
  • 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"

然后,它会再次运行几次以查找行开头的任何匹配项。

([^"]*"){2}替换为[^"]*"[^"]*"会以一个字符的代价降低复杂度吗? - potong

3

已编辑

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

这可能是最简单的方式来得到你想要的结果。

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

    print $0
  }
' file > outputFile

1

这可能适合您:

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

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;
}

未经测试,甚至未编译。特别是反斜杠的处理,很可能存在漏洞。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接