【问题标题】:BASH extract value after string in variable Not file [duplicate]BASH在变量Not文件中的字符串后提取值[重复]
【发布时间】:2021-04-30 12:36:13
【问题描述】:

我发现了一个我无法解决的奇怪问题。

我需要在一个变量中提取一些值,这些值在一个字符串之后。

本例中的变量名是:DSLSTATE

这里有一个值的例子:

NewEnable 1
NewStatus Up
NewDataPath Fast
NewUpstreamCurrRate 21598
NewDownstreamCurrRate 170788
NewUpstreamMaxRate 25692
NewDownstreamMaxRate 170788
NewUpstreamNoiseMargin 90
NewDownstreamNoiseMargin 60
NewUpstreamAttenuation 150
NewDownstreamAttenuation 170
NewATURVendor 41564d00
NewATURCountry 0400
NewUpstreamPower 486
NewDownstreamPower 514

这不是一个数组。

提取我想要的价值:

ATTUPSTREAM=$(echo "$DSLTATE" | awk '{for (I=1;I<NF;I++) if ($I == "NewUpstreamAttenuation") print $(I+1)}')

在本例中,该值应为 150,但始终为空。

奇怪的是,我可以使用相同的命令从同一个变量中提取所有值,除了示例之一。 如果我在终端上执行相同的命令,它可以工作,在脚本中不起作用。

这里是脚本的摘录:

UPSTREAM=$(echo $DSLSTATE | awk '{for (I=1;I<NF;I++) if ($I == "NewUpstreamCurrRate") print $(I+1)}')
DOWNSTREAM=$(echo $DSLSTATE | awk '{for (I=1;I<NF;I++) if ($I == "NewDownstreamCurrRate") print $(I+1)}')
ATTUPSTREAM=$(echo $DSLTATE | awk '{for (I=1;I<NF;I++) if ($I == "NewUpstreamAttenuation") print $(I+1)}')
ATTDOWNSTREAM=$(echo $DSLSTATE | awk '{for (I=1;I<NF;I++) if ($I == "NewDownstreamAttenuation") print $(I+1)}')
SNRUPSTREAM=$(echo $DSLSTATE | awk '{for (I=1;I<NF;I++) if ($I == "NewUpstreamNoiseMargin") print $(I+1)}')
SNRDOWNSTREAM=$(echo $DSLSTATE | awk '{for (I=1;I<NF;I++) if ($I == "NewDownstreamNoiseMargin") print $(I+1)}')

这些是结果:

ATTUPSTREAM=
ATTDOWNSTREAM=170
SNRUPSTREAM=40
SNRDOWNSTREAM=50

也许 DSLSTATE 变量中的值之间的间距有一些奇怪的字符?

希望有人能启发我。

【问题讨论】:

  • 你为什么不直接做ATTUPSTREAM=$(awk '/NewUpstreamAttenuation/{print $2}' &lt;&lt;&lt; $DSLTATE)?如果您将搜索字符串替换为相应的值,这也适用于所有其他值。
  • 不要对 awk 或未导出的 shell 变量使用全部大写的名称,以避免与内置变量和其他原因发生冲突,例如有关 shell 问题,请参阅 stackoverflow.com/questions/673055/…
  • 这是我评论中的错字。
  • 在 OPs 代码中也有错字 - 我强烈怀疑 @rowboat 解决了这个问题。
  • @accdias 我几乎不是 shell 脚本的大师,但这是我的反馈 FWIW - 它使用了一个不可移植的字符串化构造 &lt;&lt;&lt; 并且 OP 没有告诉我们他们是哪个 shell使用这样可能对他们不起作用,如果一个标签是另一个标签的一部分,它会失败,例如假设您在输入中有NewUpstreamAttenuationNewUpstreamAttenuationMax - 该脚本将打印这两个值,并且(可能不太可能)如果任何标签包含正则表达式元字符,例如The.Max,那么你需要确保逃脱它们。

标签: bash awk extract


【解决方案1】:
  1. 不要对 awk 或未导出的 shell 变量使用全部大写的名称,以避免与内置变量和其他原因发生冲突,例如有关 shell 问题,请参阅 Correct Bash and shell script variable capitalization

  2. 当输入为 总是在标签-值对中。

  3. 当你有通用代码时,把它 在一个函数中,不要重复多次——据我们所知 代码中可能存在控制字符或其他问题 一个标签值。

首先更改您的代码以使用简单的查找函数:

$ tag2val() { echo "$DSLSTATE" | awk -v tag="$1" '$1==tag { print $2 }'; }

$ tag2val NewDataPath
Fast

$ tag2val NewUpstreamAttenuation
150

如果您仍有问题,请告诉我们。如果您这样做,请编辑您的问题以显示echo "$DSLSTATE" | cat -Ev 的输出。

【讨论】:

  • 您好,感谢您在这里的糟糕编码......多次重复代码是一种不好的态度,我将更改代码。
  • 即使使用 awk 的 print $2 部分的功能,我仍然遇到问题。变量之间似乎存在一些差异......这就是我首先将 awk 与循环一起使用的主要原因。主要问题是当 echo 将值视为唯一行时,当列表
  • echo 不会那样做。您的变量中没有换行符,或者更有可能给定您问题中的代码,您正在从 echo "$DSLSTATE" 中删除双引号,因此除其他外,要求 shell 传递 @ 中的每个非空白字符串987654327@ 到 echo 作为单独的参数,而不是一个单独的参数。理解 shell 中的引用非常重要 - 请参阅 mywiki.wooledge.org/Quotes
【解决方案2】:

如果您使用的是 Bash,另一种选择是将 DSLSTATE 转换为关联数组。之后,根据key获取值会更容易:

#!/bin/bash

DSLSTATE='NewEnable 1
NewStatus Up
NewDataPath Fast
NewUpstreamCurrRate 21598
NewDownstreamCurrRate 170788
NewUpstreamMaxRate 25692
NewDownstreamMaxRate 170788
NewUpstreamNoiseMargin 90
NewDownstreamNoiseMargin 60
NewUpstreamAttenuation 150
NewDownstreamAttenuation 170
NewATURVendor 41564d00
NewATURCountry 0400
NewUpstreamPower 486
NewDownstreamPower 514'

declare -A kv

while read k v; do
    kv[$k]=$v
done <<< $DSLSTATE

echo "NewDownstreamPower: ${kv[NewDownstreamPower]}"

上面的代码会导致:

NewDownstreamPower: 514

【讨论】:

    猜你喜欢
    • 2016-02-06
    • 2022-01-06
    • 2021-11-13
    • 2019-03-28
    • 2016-08-30
    • 2019-06-22
    • 1970-01-01
    • 2018-09-23
    • 2019-11-12
    相关资源
    最近更新 更多