【问题标题】:Reading a file in a shell script and selecting a section of the line在 shell 脚本中读取文件并选择行的一部分
【发布时间】:2014-09-09 10:48:17
【问题描述】:

这可能很基本,我想读入一个出现文件。

那么程序应该在文件Hendelse.logg中找到所有出现的"CallTilEdb"

CallTilEdb 8 呼叫客户 9 CallTilEdb 4 客户Chk 10 客户Chk 15 CallTilEdb 16

然后总结右栏。对于这种情况,它将是 8 + 4 + 16,所以我想要的输出是 28

我不知道该怎么做,这是我对vistid.sh的了解:

#!/bin/bash
declare -t filename=hendelse.logg
declare -t occurance="$1"
declare -i sumTime=0

while read -r line
do
    if [ "$occurance" = $(cut -f1 line) ]       #line 10
    then
        sumTime+=$(cut -f2 line)
    fi
done < "$filename"

所以终端中的执行将是

vistid.sh CallTilEdb

但我现在得到的错误是:

/home/user/bin/vistid.sh: 第 10 行: [: 一元运算符预期

【问题讨论】:

  • 什么是“发生故障”?
  • @John 我试图清理这个问题,那个词已经消失了。
  • @JohnZwinck 我的意思是写发生 fex。(例如发生)
  • @Tomalak 谢谢 :) 我对 Shell Scripting 很陌生,因此我的术语有点偏离 :P 抱歉。
  • @Patidati:在美式和英式英语中,“feks”和“fex”通常都不能理解为“例如”。人们通常写“例如”、“例如”或“例如”。

标签: bash shell cut


【解决方案1】:

你有一个不错的方法,但也许你可以使用awk 来做同样的事情......更快!

$ awk -v par="CallTilEdb" '$1==par {sum+=$2} END {print sum+0}' hendelse.logg
28

如果您到目前为止还没有使用过 awk,它可能看起来有点奇怪,但它的作用如下:

  • -v par="CallTilEdb"awk 提供一个参数,以便我们可以在脚本中使用par 作为变量。如果您想使用提供给脚本的变量作为参数,也可以使用-v par="$1"
  • $1==par {sum+=$2}这意味着:如果第一个字段与变量par的内容相同,则将第二列的值添加到计数器sum中。
  • END {print sum+0} 这意味着:处理完文件后,打印sum 的内容。 +0 使 awk 打印 0 以防 sum 未设置...也就是说,如果没有找到。

如果你真的想用 bash 来做,你可以使用 read 和两个参数,这样你就不必使用 cut 来处理值,再加上一些 arithmetic operations 来对值求和:

#!/bin/bash
declare -t filename=hendelse.logg
declare -t occurance="$1"
declare -i sumTime=0

while read -r name value                  # read both values with -r for safety
do
    if [ "$occurance" == "$name" ]; then  # string comparison
       ((sumTime+=$value))                # sum
    fi
done < "$filename"

echo "sum: $sumTime"

所以它是这样工作的:

$ ./vistid.sh CallTilEdb
sum: 28
$ ./vistid.sh CustomerChk
sum: 25

【讨论】:

  • 谢谢!我将尝试这两种方法来实践它,非常好的和简单的解释,实际上是有道理的:)!
  • @Patidati 很高兴读到这一点 :) 注意我添加了一个 bash 版本,因为您可以使用 read -r name value 并摆脱所有那些 cuts。
  • 那行得通(bash 版本)非常感谢 :) 现在将检查 awk 版本;)
  • @Patidati 当然!从How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?,“-r 选项到read 防止反斜杠解释(通常用作反斜杠换行符,以继续多行)。没有这个选项,输入中的任何反斜杠都将被丢弃。你应该几乎始终将-r 选项与读取一起使用。”因此,这是一种防止文件中的奇怪字符导致奇怪行为的安全措施。
  • 再一次,完美的解释:) 谢谢:)!
【解决方案2】:

首先你需要改变你调用cut的方式:

$( echo $line | cut -f1 )

在第 10 行,您错过了评估:

if [ "$occurance" = $( echo $line | cut -f1 ) ]

然后您可以通过以下方式求和:

sumTime=$[ $sumTime + $( echo $line | cut -f2 ) ]

但您也可以使用不同的方法并将行值放入一个数组中,最终脚本将如下所示:

#!/bin/bash
declare -t filename=prova
declare -t occurance="$1"
declare -i sumTime=0

while read -a line
do
    if [ "$occurance" = ${line[0]} ]
    then
        sumTime=$[ $sumtime + ${line[1]} ]
    fi
done < "$filename"

echo $sumTime

【讨论】:

  • 只是想快速发布一下我正在阅读这些内容并尝试一下;)
  • Ok :) 尝试第一个没有数组的方法,之后将尝试数组方法。现在的问题是,在第 10 行我收到此错误: 在第 12 行:
【解决方案3】:

供参考,

id="CallTilEdb"
file="Hendelse.logg"

sum=$(echo "0 $(sed -n "s/^$id[^0-9]*\([0-9]*\)/\1 +/p" < "$file") p" | dc)
echo SUM: $sum

打印

SUM: 28
  • sed 从包含给定 id 的行中提取数字,例如 CallTilEdb
  • 并以number + 格式打印它们
  • echo 准备了一个字符串,例如 0 8 + 16 + 4 + p 什么是 RPN 格式的计算
  • dc 进行计算

另一种变体:

sum=$(sed -n "s/^$id[^0-9]*\([0-9]*\)/\1/p" < "$file" | paste -sd+ - | bc)
#or
sum=$(grep -oP "^$id\D*\K\d+" < "$file" | paste -sd+ - | bc)
  • sed(或 grep)仅提取和打印数字
  • 粘贴会生成一个类似number + number + number 的字符串(-d+ 是一个分隔符)
  • bc 进行计算

或perl

sum=$(perl -slanE '$s+=$F[1] if /^$id/}{say $s' -- -id="$id" "$file")
sum=$(ID="CallTilEdb" perl -lanE '$s+=$F[1] if /^$ENV{ID}/}{say $s' "$file")

【讨论】:

    【解决方案4】:

    Awk 翻译成脚本:

    #!/bin/bash
    declare -t filename=hendelse.logg
    declare -t occurance="$1"
    declare -i sumTime=0
    
    sumtime=$(awk -v entry=$occurance '
                                       $1==entry{time+=$NF+0}
                                      END{print time+0}' $filename)
    

    【讨论】:

    • 无需声明time。一旦你开始使用它,它就会被定义。看看我的方法。
    • 嗨,如果没有找到条目,则会抛出“void”结果。无论如何都要 +1
    • 真的!在这种情况下,使用END {print time+0} 来确保您将打印time0 会很方便。
    猜你喜欢
    • 1970-01-01
    • 2014-02-24
    • 2021-06-02
    • 1970-01-01
    • 1970-01-01
    • 2019-02-10
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多