Bash 字符串在 space 标记处从数组输出时被截断

Bash strings getting cut off when outputting from array at space marks

所以我正在查看一个日志文件并从所述日志文件中提取信息,例如设备名称、位置和日志时间。它看起来像下面这样:

edge2.mco1-9 Jun 11:32:24 GMT %SEC_LOGIN-5-LOGIN_SUCCESS: Login Success

我遇到一个问题,当我 运行 以下内容时:


for y in ${DeviceName[@]}
do
    echo "Device: $y"
    counter=1
    for z in ${LocationName[@]}
    do
        testing=($(grep "$y\.$z\-.*\%" hacker.txt | cut -f2 -d "-" | cut -f1 -d% | head -n 1))
        if [[ ${testing[$counter]} =~ [^0-9] ]]
        then
            echo $z
            echo $testing
        fi
        
    done
    
done

天数是唯一输出的部分。 DeviceName 是一个设备名称数组。 LocationName 是位置名称数组。复杂的部分是由于我只想输出位置名称,如果它有来自 grep 的东西,因为我不想要一长串没有时间附加的位置。我做了保存到 .txt 文件的实验,它确实做了正确的时间,但由于空格,输出正确的时间似乎更麻烦。使用示例,

9 Jun 11:32:24 GMT

应该是输出。有什么办法可以解决这个问题吗? $testing 被保留,因为尝试执行 ${testing[$counter]}$(${testing[$counter]}) 和其他方法不起作用给我错误。错误分别是 Jun./finder: line 113: Jun: command not found $testing 至少给了我天数。显然空格有问题,但我不知道如何解决这个问题。

设置:

$ cat hacker.txt
edge2.mco1-9 Jun 11:32:24 GMT %SEC_LOGIN-5-LOGIN_SUCCESS: Login Success
$ y=edge2
$ z=mco1

grep命令:

$ grep "$y\.$z\-.*\%" hacker.txt | cut -f2 -d "-" | cut -f1 -d% | head -n 1                                                                    
9 Jun 11:32:24 GMT

正在将其加载到 testing[] 数组中:

$ testing=( $(grep "$y\.$z\-.*\%" hacker.txt | cut -f2 -d "-" | cut -f1 -d% | head -n 1) )
$ typeset -p testing
declare -a testing=([0]="9" [1]="Jun" [2]="11:32:24" [3]="GMT")

运行 测试:

$ counter=1
$ [[ ${testing[$counter]} =~ [^0-9] ]] && echo "success"
success

# turn on debugging to see what we're testing:
$ set -xv                                                  # turn on debugging

$ [[ ${testing[$counter]} =~ [^0-9] ]] && echo "success"
[[ ${testing[$counter]} =~ [^0-9] ]] && echo "success"
+ [[ Jun =~ [^0-9] ]]                                      # contents of testing[1] == 'Jun'
+ echo success
success

$ set +xv                                                  # turn off debugging

到目前为止一切顺利。

OP 已声明所需的输出应如下所示:

9 Jun 11:32:24 GMT

但是当前的echo命令有一个问题:

echo $testing                                            

$testing是一个数组;没有索引 bash$testing 视为与 ${testing[0]} 相同,在这种情况下输出 9 (请参阅上面 typeset -p testing 的输出);输出数组 OP 的全部内容可以使用:

$ echo "${testing[@]}"
9 Jun 11:32:24 GMT

最终结果:OP 应该能够将 echo $testing 更改为 echo "${testing[@]}" 以获得所需的输出。


OP 提到了代码复杂化(加载 testing[] 数组,比较 testing[1] ???)是由于仅在 grep 找到匹配项时才打印输出。

我们可以通过将 for z 循环的核心替换为:

来稍微简化代码
    # no need for array, just capture datetime stamp:

    dtstamp=$(grep "$y\.$z\-.*\%" hacker.txt | cut -f2 -d "-" | cut -f1 -d% | head -n 1)

    # is length of 'dtstamp' non-zero?

    if [[ -n "${dtstamp}" ]]
    then
        echo "${z}"
        echo "${dtstamp}"
    fi

如果objective只在grep找到匹配时打印${z}(即OP不需要打印${dtstamp}),我们可以简化代码更多到 for z 循环中唯一的命令是:

grep "$y\.$z\-.*\%" hacker.txt >/dev/null && echo "${z}"

演示:

$ z=mco1
$ grep "$y\.$z\-.*\%" hacker.txt >/dev/null && echo "${z}"
mco1

$ z=xxxx
$ grep "$y\.$z\-.*\%" hacker.txt >/dev/null && echo "${z}"
              <<<=== no output

备注:

  • 也可以从当前代码中删除counter=1
  • OP 应该考虑 cutting-n-pasting 他们的代码(以及适当的 shebang,例如 #!/bin/bash)到 shellcheck.net;这将报告语法问题并提出一些建议:'best practices'