首页 > 解决方案 > AWK 在单行中传递多个命令

问题描述

我想将以下多个 awk 命令组合成一个 awk 程序:

awk -F 'FS' '{ $1 = ($1 == "}" ? "" : $1) } 1' sorce > destfil
awk -F 'FS' '{ $3 = ($3 == "]" ? "" : $3) } 1' sorce > destfil
awk -F 'FS' '{ $5 = ($5 == "}" ? "}," : $5) } 1' sorce > destfil

我曾尝试使用来完成此操作&&,但结果不是我所期望的。

awk -F 'FS' '{ $1 = ($1 == "}" ? "" : $1) &&  $3 = ($3 == "]" ? "" : $3) && $5 = ($5 == "}" ? "}," : $5) } 1' sorce > destfil

输出中似乎有各种零。

问题:

谢谢!


@RavinderSingh13,当我尝试您的代码、示例输入文件和输出文件时,如下所示

[user@restt]$ tail source
    {
    }
  ]
}
{
  " e t
    {
    }
  ]
}
[user@test]$ awk -F 'FS' '{$1=($1=="}"?"":$1); $3=($3=="]" ? "" : $3) ; $5=($5=="}" ? "}," :$5);} 1' source > target
[user@test]$ tail target
    {
    }
  ]
}
{
  " e t
    {
    }
  ]
}

我认为这个问题与字段分隔符 -F 'FS' 有关,或者我不确定。


@kvantour,下面我给出了我的示例输入文件和命令我正在运行什么我得到什么输出我需要什么。

源文件内容:

{
  "metadata": [
    {
      sample content line 1
      sample content line n


    }
  ]
}
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    }
  ]
}
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    }
  ]
}
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    }
  ]
}

我正在运行的命令

$ awk '($1=="}"){$1="First Column"}
       ($3=="]"){$3="third Column"}
       ($5=="}"){$5="Fifth Column"}
       {$1=$1}1' sample.json > out

我得到的输出:

[root@centos-src ~]# cat out

{
"metadata": [
{
sample content line 1
sample content line n


First Column
]
First Column
{
"metadata": [
{
sample content line 1
sample content line n


First Column
]
First Column
{
"metadata": [
{
sample content line 1
sample content line n


First Column
]
First Column
{
"metadata": [
{
sample content line 1
sample content line n


First Column
]
First Column

但我期望输出是:

{
  "metadata": [
    {
      sample content line 1
      sample content line n


    Fifth Column
  third Column
First Column
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    Fifth Column
  third Column
First Column
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    Fifth Column
  third Column
First Column
{
  "metadata": [
    {
      sample content line 1
      sample content line n


    Fifth Column
  third Column
First Column

标签: bashawk

解决方案


在一个不错的 awk 结构中,可以这样写:

awk -F 'FS' '($1=="}"){$1=""}
             ($3=="]"){$3=""}
             ($5=="}"){$5="},"}
             {$1=$1}1' <file>

我添加$1=$1到列表中的原因是在不满足上述条件的情况下重新处理$0正确。OFS如果您不这样做,您将打印出FS作为字段分隔符的行,而其他行将打印为OFS.

那么为什么你会得到一堆零呢?

让我们看看你的单线:

$1 = ($1 == "}" ? "" : $1) &&  $3 = ($3 == "]" ? "" : $3) && $5 = ($5 == "}" ? "}," : $5)

并通过假设括号之间的三元运算符返回一个变量来简化它。所以我们可以将其重写为:

$1 = var1 && $3 = var3 && $5 = var5

考虑到:

  • expr1 && expr2的优先级高于value = expr
  • lvalue = expr返回 expr 的值

我们可以看到 awk 将其解释为

$1 = var1 && ($3 = (var3 && ($5 = var5) ) )

所以结果将是:

$5 = var5
$3 = var3 && $5  equalling var3 && var5
$1 = var1 && $3  equalling var1 && var5

这在以下示例中可见:

$ echo "a b c d e f" | awk '{ $1="p" && $3 = "q" && $5 = "r"}1'
1 b 1 d rf

最后,在awk空字符串和数字零中,逻辑值false和其他任何值true。因此,由于您的两个原始三元运算符可以返回空字符串,它们将确保逻辑 AND 将返回 false,这相当于数字零。因此,如果原始等于,则$1$3都将与零匹配$3]

更新(收到 [mcve] 后)

你试图达到的目标并不是那么容易。首先,您似乎假设列号意味着行中的字符号。可悲的是,情况并非如此。在默认模式下,awk 假定字段$nn行中的第一个单词,其中单词是不包含任何空格的字符序列。所以在下面的文字中,

    }
  ]
}

所有字符实际上都由$1.

在您的 JSON 文件完全缩进的假设下,可以使用以下内容:

awk '/^} *$/{$0="First Column"}
     /^  ] *$/{$0="  Thrid Column"}
     /^    } *$/{$0="    Fifth Column"}
     {print $0}' <file>

但是,如果您的 JSON 文件没有统一缩进,事情就会变得相当混乱。最简单的方法是首先使用jqas解析文件

jq . <json-file> | awk ...

推荐阅读