sed 通过管道删除字符的最后一个实例?

sed 通过管道删除字符的最后一个实例?

我在多行变量中有一个生成的 json 数组,但我需要删除最后一个逗号,如 in [{"name":"a"},{"name":"b"},{"name":"c"},],独立于格式、换行符或空格。

我正在尝试使用来自的答案这个问答但我使用变量而不是文件作为输入:

例如 sed 版本:

echo "$json" | sed -n 'x;${s/,$//;p;x}; 2,$ p'

我正在对示例进行相同的尝试,awk但没有成功。

我可以使用管道得到的唯一答案是在 perl 页面的更下方echo "$json" | perl -0777 -pi -e 's/(.*),(.*?)/\1\2/s'

我更愿意使用sed而不是perl作为本地设置forperl并不总是在我管理的机器上设置。

如何修改 sed 命令以与管道一起使用?

答案1

您所采取的(出色的顺便说一句)答案仅适用于倒数第二行的更改。

如果你只有一根线,那就容易多了;像@I_GNU_it_all_along 建议替换,]]

echo "$json" | sed 's/,]/]/'

或者,使用 GNU 删除文件中最后一个字符实例的一般解决方案sed

echo "$json" | sed -z 's/\(.*\),/\1/'

它有什么作用?该-z选项指示sed立即处理整个缓冲区而不是逐行处理,因此我们只需替换缓冲区中的最后一个逗号即可。

不幸的是,您可以轻松删除第一个逗号 ( s/,//) 或第 42 个逗号 ( s/,//42),但不能删除最后一个逗号(类似的操作s/,//$未实现)。

因此,我们利用“贪婪” *.*将匹配尽可能多的字符,因此.*,将匹配直到最后一个逗号的所有字符。但我们只想删除最后一个逗号,因此我们用 包围其他所有内容,\(\)并且可以在替换中重用该部分作为\1

-z如果您的 中没有该选项sed,则必须手动收集缓冲区中的所有行:

echo "$json" | sed 'H;1h;$!d;x;s/\(.*\),/\1/'

答案2

这是 JSON 特定的问题:如果最后一个数组项后跟逗号,,任何 JSON 验证器都会抛出一个错误,告诉它是Expected another array element at line ....

尝试awk解决方案:

示例 json 文件input.json(无效):

[
  {
    "name": "a"
  },
  {
    "name": "b",
    "keys": [
        1,2,3,
    ]
  },
  {
    "name": "c"
  },
]

awk -v RS= '{ gsub(/,[[:space:]]*]/, "\n]", $0) }1' input.json | jq '.'

输出(通过管道传输杰克):

[
  {
    "name": "a"
  },
  {
    "name": "b",
    "keys": [
      1,
      2,
      3
    ]
  },
  {
    "name": "c"
  }
]

答案3

,]为什么不直接将的实例替换为]

echo "$json" | sed 's/,]/]/'

相关内容