【问题标题】:How can I check (and delete) if the last line (that contains the last occurence of a string) has a comma as last character?如何检查(和删除)最后一行(包含最后一次出现的字符串)是否有逗号作为最后一个字符?
【发布时间】:2016-01-19 15:46:58
【问题描述】:

我一直在寻找整个互联网,但没有结果。

我正在尝试构建一个包生成器(在 shell/bash 中),并且相应的包包含(一个或多个)json 文件。浏览 json 文件时,如果用户想要删除其中一个步骤,我必须首先考虑如果他要删除的步骤是最后一个步骤。如果是这样,最后一步的前面将包含一个逗号,但 json 格式不允许这样做。

{
  "operation_machinetype": "Ford",
  "operation_steps": [
    "steps/Step_1/01_paint_the_car.json",
    "steps/Step_2/01_drive_the_car.json",
    "steps/Step_2/02_park_the_car.json"
  ]
}

例如,如果我删除 '"steps/Step2/02_park_the_car.json"',则 '"steps/Step2/01_drive_the_car.json",' 将是最后一步,但逗号会导致错误。

提前谢谢大家。

【问题讨论】:

  • 虽然json 是人类可读的(以及任何其他格式,例如xmlini 等),但需要一些如何编辑它的知识。您可以轻松搞砸[ ]{ }, 只是长长的必须知道该做什么列表中的另一点。判决 - 什么都不做。
  • 感谢您花时间写一些东西。我知道我应该如何删除行 ' sed "/$2/d" $1 ' 但逗号仍然存在:)

标签: linux bash shell awk sed


【解决方案1】:
$ cat tst.awk
index($0,tgt) {
    if (!/,[[:space:]]*$/) {
        sub(/,[[:space:]]*$/,"",prev)
    }
    next
}
NR>1 { print prev }
{ prev = $0 }
END { print prev }

$ awk -v tgt='"steps/Step_2/02_park_the_car.json"' -f tst.awk file
{
  "operation_machinetype": "Ford",
  "operation_steps": [
    "steps/Step_1/01_paint_the_car.json",
    "steps/Step_2/01_drive_the_car.json"
  ]
}

$ awk -v tgt='"steps/Step_2/01_drive_the_car.json"' -f tst.awk file
{
  "operation_machinetype": "Ford",
  "operation_steps": [
    "steps/Step_1/01_paint_the_car.json",
    "steps/Step_2/02_park_the_car.json"
  ]

【讨论】:

  • 但是你用awk标记了这个问题?无论如何 - 它是所有 UNIX 安装的标准通用文本操作工具。它充满了旨在让您在处理文本时更轻松的结构(例如,隐式读取时读取循环、内置条件/操作块、将行拆分为字段、跟踪读取的行数、一行中的字段数、能够处理整个段落,而不是行等),它是一种脚本语言,但执行此任务的速度与 C 一样快。获取 Arnold Robbins 所著的《Effective Awk Programming, 4th Edition》一书。
  • 感谢您的描述和建议!。将验证这一点并返回更新。
  • 不客气。请注意,awk 脚本将您要删除的字符串完全视为 string。 sed 不能对字符串进行操作,只能对正则表达式进行操作,因此如果您想让 sed 将正则表达式视为字符串,那么您需要通过转义它们来禁用所有正则表达式元字符。有关该主题和解决方案的讨论,请参阅stackoverflow.com/q/29613304/1745001。 sed 是在单个行上进行简单替换的正确工具,但对于更有趣的事情,例如这样,您应该使用 awk 来提高清晰度、可移植性、健壮性等。
  • 是的,您可以使用任何命令重定向输出,但概要是 cmd file > tmp && mv tmp file,而不是您编写的内容,如果命令失败并且使用 @ 987654325@ arg 为 rm 不受欢迎。 awk 脚本将按原样进行部分匹配,您应该刚刚尝试过。
  • 我试过了 :) 我不知道是人为错误还是其他原因,但起初它没有删除。标记为最终答案。感谢您的帮助!
【解决方案2】:

您可以使用多行正则表达式查找右括号前的最后一个逗号,例如:

/,\s*]/g

查看refiddle上的示例

【讨论】:

  • 虽然这是一个有效的选项,但我希望尽可能地独立于括号;只想与“步骤”行相关。我还看到了一些使用“tac”的答案,反转然后搜索第一次出现(如果它包含逗号作为最后一个字符),但在这种情况下重写它没有运气。再次感谢!
  • 然后使用yaml 并告别括号:)
  • 不幸的是我被阻止使用这种格式:) 我应该支持你的答案吗?我是新来的。
  • 您到底想实现什么?可以尝试解析json文件,如果有问题通知用户。
  • 我有数百个这样的文件,每个都打包在一个 tgz 存档中。我需要完全自动化,而不是手动进行数千次更改。
【解决方案3】:

我知道该类别是 bash,但您一般应该使用可识别 JSON 的东西,而不仅仅是像基于行那样编辑文件。那么您就不必担心正确的 json 编码,而可以专注于操作数据。由于内置的​​ json 支持和相对普遍性(并且因为这在 Python 中非常简单),我倾向于使用 Python。也许像这个简单的脚本(其中一半以上是错误检查冗长):

#!/bin/env python
import json
import sys

if( len(sys.argv)-1 != 2 ):
  sys.stdout.write('Usage: ' + sys.argv[0] + ' pattern file\n')
  sys.exit(1)

patt = sys.argv[1]
filename = sys.argv[2]

with open(filename, 'r') as data_file:
  data = json.load(data_file)

try:
  data["operation_steps"].remove(patt)
except ValueError:
  sys.stdout.write( 'Pattern "' + patt + '" not found in '
                    + filename + '; leaving file unchanged\n' )
  sys.exit(2)

sys.stdout.write( 'updating ' + filename + '\n' )
with open(filename, 'w') as data_file:
  json.dump(data, data_file, ensure_ascii=False, indent=2)

如果您从 json.dump 调用中删除“indent=2”,它也会压缩 json - 这可能有助于减少包中浪费的空间。 :)

那里有几个命令行 json 操纵器,我一直在为 ksh93 编写一个基于 C 的可加载模块,但如果我今天打算这样做。

【讨论】:

  • 实际上我确实想在不久的将来将它迁移到 Python,也许是使用 WX 的一个不错的图形界面,但在那之前我仍然需要它在 sed/awk 中。也许我可以在我尝试的时候用更多的问题来打扰你,当然,如果你不介意的话。谢谢!!
  • 我绝不是 Python 专家,但我总是很乐意提供我能提供的指导。顺便说一句,如果需要内联代码和单独的脚本,请考虑stackoverflow.com/a/2356490/65589
  • 你好,丹尼绍尔。我决定将整个事情迁移到 python,因为 awk 太 (awk)ward 无法为如此复杂的事情提供快速解决方案。 :) 我使用了您的示例,但不幸的是,当我使用字符串作为模式时,它没有找到相应的步骤。
  • list.remove() 将要删除的对象作为参数,因此对于字符串,它必须是 exact 匹配。我确实测试了示例代码以验证它是否有效,因此您的任务显然是找出您的字符串有何不同。 :)
【解决方案4】:

这可能对你有用(GNU sed):

sed 'N;s#,\s*\n\s*"steps/Step_2/02_park_the_car\.json"##;P;D' file

这一次读取两行,如果找到匹配项,则删除所需的字符串。它打印然后删除第一行,然后追加下一行。

注意如果模式空间为空,它会读取另一行,然后追加下一行。

【讨论】:

  • 也会检查这一点并马上回来更新!谢谢。
  • 您应该转义 . 并注意可能出现在文件名中的任何其他 RE 元字符(或 #,因为您将其用作分隔符`)。
  • 不幸的是,这仅显示文件的全部内容,并且不会以任何方式更改它。不过,感谢您的宝贵时间。
  • @digital_critic 也许在包含, 的第一行末尾有空格。我已经修改了解决方案来解决这个问题,并引用了@Ed Morton 提到的.
  • 我一次又一次地尝试,但仍然无法正常工作。 :(
【解决方案5】:

您可以考虑使用 YAML:

---
  operation_machinetype: "Ford"
  operation_steps: 
    - "steps/Step_1/01_paint_the_car.json"
    - "steps/Step_2/01_drive_the_car.json"
    - "steps/Step_2/02_park_the_car.json"

【讨论】:

    猜你喜欢
    • 2012-06-05
    • 2018-09-19
    • 2021-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-31
    • 2020-03-12
    相关资源
    最近更新 更多