【问题标题】:Dynamic continuous numbering in bashbash中的动态连续编号
【发布时间】:2018-02-21 03:53:58
【问题描述】:

我有一个文本文件作为我的脚本的数据库。在示例中,该文件有一个“ID”列。

数据库的格式为 UID:商品名称:数量:价格:添加日期

cat FirstDB.txt

输出:

0001:Fried Tarantula:45:100:2017-08-03
0002:Wasp Crackers:18:25:2017-08-04
0003:Century Egg:19:50:2017-08-05
0004:Haggis Flesh:20:90:2017-08-06
0005:Balut (Egg):85:15:2017-08-07
0006:Bear Claw:31:550:2017-08-08
0007:Durian Fruit:70:120:2017-08-09
0008:Live Cobra heart:20:375:2017-08-10
0009:Monkey Brains:30:200:2017-08-11
0010:Casu Marzu:25:1030:2017-08-12

现在我正在创建的功能允许某个用户使用相同的格式在文本文件中输入新条目(我已经创建了这个)。然而,这里真正的诀窍是用户还可以选择删除某个项目。例如,用户想从文本文件中删除 Century Egg,输出将是这样的:

0001:Fried Tarantula:45:100:2017-08-03
0002:Wasp Crackers:18:25:2017-08-04
0004:Haggis Flesh:20:90:2017-08-06
0005:Balut (Egg):85:15:2017-08-07
0006:Bear Claw:31:550:2017-08-08
0007:Durian Fruit:70:120:2017-08-09
0008:Live Cobra heart:20:375:2017-08-10
0009:Monkey Brains:30:200:2017-08-11
0010:Casu Marzu:25:1030:2017-08-12

然后,如果用户希望在数据库中添加任何项目,我希望用户使用 UID 0003,因为它已经是免费的。我该如何实现这一目标?到目前为止,我一直坚持下去。我相信awk 在这里很有用,但我并没有关闭我的选项,而且我对脚本编写还很陌生,而且我对awk 还不是很好。因此,如果您有一个使用awk 的解决方案,请指导我完成它。非常感谢!

【问题讨论】:

  • 向我们展示您的程序以及您遇到的问题。 Stack Overflow 是为了帮助让程序运行(或让它们运行得更好),而不是为你做你的工作。
  • 您的脚本是否将文件加载到内存中并主要处理内存版本的数据(效率更高),或者脚本是否不断(重新)读取/(重新)写入文件(效率较低) ?如果是以前的(加载/工作)内存,您如何将数据存储在脚本中?
  • 我陷入了一种我几乎不知道从哪里开始脚本动态编号的功能我所知道的是我可以通过使用 @ 来减少文本文件987654328@ 并从那里我将有一个我可以使用的数字列表。从那里开始,我实际上对如何进行比较和增量一无所知,如果我听起来像是要求堆栈溢出为我工作,我很抱歉,因为我对所有这些都是新手。
  • 我最近发布了这个问题的答案。我没有时间去搜索它,但如果你在过去几个月里浏览我所有的答案,它就在某个地方......

标签: arrays bash awk sed text-manipulation


【解决方案1】:

awk 来救援!

假设编辑后序列将不再排序

awk -F: '{a[$1+0]} END{for(i=1;i<=NR;i++) if(!(i in a)) print i}'

将返回第一列中第一个缺失的数字(假设为数字字段)。

测试

创建一个无“0003”缺失的格式化序列号的打乱列表。

awk 'BEGIN{for(i=1;i<=10;i++) printf "%04d\n",i}' | shuf | awk '$1!=3' 

0009
0001
0006
0004
0002
0005
0008
0010
0007

到脚本的管道

... | awk -F: '{a[$1+0]} END{for(i=1;i<=NR;i++) if(!(i in a)) print i}'

按预期返回

3

但是,如果您的列表没有空白,则不会返回任何内容。要处理这种情况,您需要返回最大的数字 + 1。通过此修改,测试用例和脚本变为

$ awk 'BEGIN{for(i=1;i<=10;i++) printf "%04d\n",i}' | 
  shuf | 
  awk -F: '{a[$1+0]} $1>max{max=$1} 
       END {for(i=1;i<=NR;i++) if(!(i in a)) {print i; exit} 
            print max+1}'

11

注意如果您在每次插入记录后对文件进行排序,则可以避免很多复杂性。

【讨论】:

  • 我将尝试使用您提供的最后一个脚本,因为这似乎正是我正在寻找的那个!谢谢!对此表示赞成并将其标记为答案。
【解决方案2】:

如果我正确理解了这个问题,您正在寻找从顶部开始的第一个“免费”号码。比如:

$ awk -F: '{s=sprintf("%04d",NR)} s!=$1{print s; exit}' FirstDB.txt

可以做你想做的事。我在这里假设没有 2 个客户端可以同时添加/删除。

这甚至可以缩短为:

$ awk -F: '(s=sprintf("%04d",NR))!=$1{print s; exit}' FirstDB.txt

【讨论】:

  • $1 != NR 作为一种更简单的编写条件的方式有什么问题?此外,您需要清楚的是,此解决方案是基于正在排序的文件(即使在添加了新元素之后)。 (您还需要END 操作。)
  • OP 没有明确要求。如果您认为输入应该是无序的,请成为我的客人。恐怕OP建议不然。
  • 我并不是说你的答案是错误的;只是值得说明这个假设。记录先决条件总是有用的。 (尽管如果您不提供END 操作,答案错误的,因为文件中的任何行的条件都可能不正确。)
  • 它什么也不打印。如预期。同样,OP 并不清楚,所以显然每个人都有自己的假设。
猜你喜欢
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 2021-03-28
  • 2023-03-11
  • 1970-01-01
  • 2021-12-03
  • 2018-08-11
相关资源
最近更新 更多