首页 > 解决方案 > Ubuntu 20.04.2 和 21.04 之间的不同脚本行为终止

问题描述

可以在 Ubuntu 21.04 上毫无问题地在 shell 脚本中运行以下命令:

grep -h "new tip" logs/node.log | tail -1000 | sed -rn "s/\[(.*)\].\[(.*)\].* ([0-9]+)/\2,\3/p" | awk -F, -v threshold=2 '{"date +%s.%3N -d\""$1"\""|getline actualTime; delay=actualTime-$2-1591566291; sum+=delay; if (delay > threshold ) print $1 " " delay;} END {print "AVG=", sum/NR}'

但是当我在 Ubuntu 20.04.2 上运行完全相同的脚本时,我得到了这个错误:

/bin/sh: 1: Syntax error: Unterminated quoted string

这绝对是完全相同的脚本,因为我从 21.04 到 20.04.2 对它进行了 scp'd。在 stackoverflow 或整个互联网上找不到解决此差异的任何主题。两个 Ubuntu 都在 Linux 云服务器上。关于没有错误运行脚本的唯一方法是取出这一awk"date +%s.%3N -d\""$1"\""|getline actualTime

我尝试使用对该$1字段的引用,但没有任何效果。nawk用代替尝试过awk,但没有运气。也许作为最后的手段,我可​​以将操作系统从 v 20 升级到 v 21。

有没有人见过这个?

补充:感谢大家的快速回复。这是脚本运行的日志文件的第一行

[Relaynod:cardano.node.ChainDB:Notice:60] [2021-06-30 02:20:14.36 UTC] 链扩展,新提示:de56b9f458e8942ca74c6a1913dc58fa896823dc19b366285e15481f434ed337 在插槽 33453323 [Relayno] [ChainDB:Noticed:cardano] 2021-06-30 02:20:15.17 UTC] 链延长,新提示:e88ea4f438944bd15186fe93f321c117ec769cfbd33667654634f4510cfd3780 在插槽 33453324

只是为了确保这不是数据问题。我在 Ubuntu 21 服务器上针对文件运行脚本(工作),然后将文件复制到 Ubuntu 20 服务器并针对复制的文件运行完全相同的脚本,并得到错误。

我将尝试有关此主题的建议,并让每个人都知道答案。

新更新:笔记本电脑崩溃和更换后,记得回到这个帖子。我最终像 Ed 提到的那样使用 mktime。它现在正在工作。

外壳脚本:

#!/bin/bash grep -h "新提示" logs/node.log | 尾-1000 | sed -rn "s/[(.)].[(.)].* ([0-9 ] +)/\2,\3/p" | mawk -F, -v 阈值=2 -f check_delay.awk

awk 脚本:

BEGIN{ ENVIRON["TZ"] = "UTC"; }
{
  year = substr($1,1,4);
  month = substr($1,6,2);
  day = substr($1,9,2);
  hour = substr($1,12,2);
  min = substr($1,15,2);
  sec = substr($1,18,2);
  timestamp = year" "month" "day" "hour" "min" "sec;
  actualTime=mktime(timestamp) + 7200;
        delay=actualTime-$2-1591566291;
        sum+=delay;
        if (delay >= threshold )
                print $1 " " delay;}
END {print "AVG=", sum/NR}

标签: linuxshellawkubuntu-20.04

解决方案


您正在使用数据date中恰好包含的任何值生成一个 shell 来调用$1,因此结果将取决于您的数据。看:

$ echo '3/27/2021' | awk '{"date +%s.%3N -d\""$1"\"" | getline; print}'
1616821200.000

$ echo 'a"b' | awk '{"date +%s.%3N -d\""$1"\"" | getline; print}'
sh: -c: line 0: unexpected EOF while looking for matching `"'
sh: -c: line 1: syntax error: unexpected end of file
a"b

以及此命令从日志文件中输出的内容:

sed -rn "s/\[(.*)\].\[(.*)\].* ([0-9]+)/\2,\3/p"

将根据日志文件中特定行的内容而有很大差异,因为您尝试隔离的部分没有锚定并且.*在您可能打算使用 s 时使用[^]]*s。例如:

$ echo '[foo] [3/27/2021] 15 something [probably] happened at line 50'
[foo] [3/27/2021] 15 something [probably] happened at line 50

$ echo '[foo] [3/27/2021] 15 something [probably] happened at line 50' |  sed -rn "s/\[(.*)\].\[(.*)\].* ([0-9]+)/\2,\3/p"
3/27/2021] 15 something [probably,50

$ echo '[foo] [3/27/2021] 15 something [probably] happened at line 50' |  sed -rn "s/\[(.*)\].\[(.*)\].* ([0-9]+)/\2,\3/p" | awk -F, -v threshold=2 '{"date +%s.%3N -d\""$1"\""|getline actualTime; delay=actualTime-$2-1591566291; sum+=delay; if (delay > threshold ) print $1 " " delay;} END {print "AVG=", sum/NR}'
date: invalid date ‘3/27/2021] 15 something [probably’
AVG= -1591566341

如果你想这样做,那么你可以引入一个有效日期检查以避免特定的错误,例如(但显然创建一个比这更好的日期验证正则表达式):

$ echo 'a"b' | awk '$1 ~ "[0-9]/[0-9]+/[0-9]" {"date +%s.%3N -d\""$1"\"" | getline; print}'
$

但它仍然很脆弱并且非常缓慢。

您正在使用 GNU sed,-r因此您拥有或可以获得 GNU awk 并且具有内置时间函数,因此您不应该首先生成子外壳来调用 date,您应该只是使用mktime(),请参阅https://stackoverflow .com/a/68180908/1745001,这将避免这样的神秘错误,并且运行速度更快几个数量级。


推荐阅读