Bash 用单制表符替换空格,除非使用双引号

Bash 用单制表符替换空格,除非使用双引号,bash,awk,Bash,Awk,假设一个多行文件,其中的字符串由一个或多个空格分隔。进一步假设字符串组可以用双引号括起来 > cat file foo bar "foobar baz qux" foo "bar foobar baz" qux "foo bar foobar" baz qux # multiple whitespaces in this line 如果我希望使用如下所列的awk将双引号外的所有空格替换为单制表符,我将收到以下消息: awk '{OFS="\t"; FPAT="([^, ]+)

假设一个多行文件,其中的字符串由一个或多个空格分隔。进一步假设字符串组可以用双引号括起来

> cat file
foo bar "foobar baz qux"
foo "bar foobar baz" qux
"foo   bar foobar" baz   qux   # multiple whitespaces in this line
如果我希望使用如下所列的awk将双引号外的所有空格替换为单制表符,我将收到以下消息:

awk '{OFS="\t"; FPAT="([^, ]+)|(\"[^\"]+\")"; $1=$1; print}' file
# foo   bar "foobar baz qux" # In this line, strings inside the quote are separated by tabs
# foo   "bar foobar baz"    qux
# "foo  bar foobar" baz qux
问题似乎只限于以双引号结尾的行

编辑1: 为了更好地了解当前的问题:

awk '{OFS="\t"; FPAT="([^, ]+)|(\"[^\"]+\")"; $1=$1; print}' file | cat -A
# foo^Ibar^I"foobar^Ibaz^Iqux"$
# foo^I"bar foobar baz"^Iqux$
# "foo   bar foobar"^Ibaz^Iqux$
编辑2: 除非输入中存在一定数量或非字母字符组合,否则答案部分中建议的两个命令都可以正常工作。以下是一个例子:

> cat file
foo_bar_baz foo foo_bar . Name=foo;product="bar baz qux"
foo_bar_baz foo foo_bar . Name=foo;product="bar baz qux"
foo_bar_baz foo foo_bar . Name=foo;product="bar baz qux"

> awk -v FPAT='"[^"]*"|[^[:blank:]]+' -v OFS='\t' '{$1=$1} 1' file | cat -A
foo_bar_baz^Ifoo^Ifoo_bar^I.^IName=foo;product="bar^Ibaz^Iqux"$
foo_bar_baz^Ifoo^Ifoo_bar^I.^IName=foo;product="bar^Ibaz^Iqux"$
foo_bar_baz^Ifoo^Ifoo_bar^I.^IName=foo;product="bar^Ibaz^Iqux"$

> awk '{$1=$1}1' OFS='\t' FPAT='"[^"]+"|[^ ]+' file | cat -A
foo_bar_baz^Ifoo^Ifoo_bar^I.^IName=foo;product="bar^Ibaz^Iqux"$
foo_bar_baz^Ifoo^Ifoo_bar^I.^IName=foo;product="bar^Ibaz^Iqux"$
foo_bar_baz^Ifoo^Ifoo_bar^I.^IName=foo;product="bar^Ibaz^Iqux"$
编辑3:
编辑2提出的这个问题将在此处进一步讨论:

使用
gnu awk
您可以轻松做到这一点:

awk -v FPAT='"[^"]*"|[^[:blank:]]+' -v OFS='\t' '{$1=$1} 1' file
foo bar "foobar baz qux"
foo "bar foobar baz"    qux
"foo   bar foobar"  baz qux

我将使用以下命令:

awk '{$1=$1}1' OFS='\t' FPAT='"[^"]+"|[^ ]+'
我通过
FPAT
变量定义了两种可能的字段:

  • 用双引号括起来的字符串
    “[^”]+”
  • 非空白字符序列
    [^]+
因为封闭字符串位于第一位,所以它具有更高的优先级

当管道连接到cat-A时,可以在SO上更好地显示结果:

awk '{$1=$1}1' OFS='\t' FPAT='"[^"]+"|[^ ]+' a.txt | cat -A
输出:

foo^Ibar^I“foobar baz qux”$
foo^I“bar foobar baz”^iqx$
“foobar foobar”^Ibaz^iqx$

您的命令工作得非常出色。但是,为什么上面的示例会在第一行中替换双引号之间的空格?这是因为您设置
FPAT
太晚了。应该像我所示从命令行或
BEGIN
块中设置,以便从第1行开始生效,例如
awk'BEGIN{OFS=“\t”;FPAT=“([^]+)|(\"[^\"]+\")"} {$1=$1}1'file
也应该适用于您。哦,您已经在评论中提到了它。我将删除我的答案,然后…@anubhava在使用您的awk命令几天后,它似乎只在非常特定的情况下有效。例如,以下文件未按预期处理:
>cat文件
foo\u-bar\u-baz-foo\u-bar.Name=foo;product=“bar-baz-qux”\nfo\u-bar\u-baz-foo-foo-bar.Name=foo;product=“bar-baz-qux”\nfo\u-bar\u-baz-foo\u-bar.Name=foo;product=“bar-baz-qux”
与用户anubhava的代码一样,以下文件未按预期处理,可能是由于存在非字母字符:
>cat文件
foo\u bar\u baz foo\u bar.Name=foo;product=“bar baz qux”\nfo\u bar\u baz foo\u bar.Name=foo;product=“bar baz qux”\nfo\u bar\u baz foo\u bar.Name=foo;product=“bar baz-qux”
您将如何调整代码以处理非字母字符的存在?@MichaelGruenstaeudl您能将该示例添加到您的问题中吗?很难在评论中理解。请不要编辑现有示例,添加新示例(甚至打开新问题)新的例子已经附加到问题中。好问题。我不知道atm。将需要对此进行调查