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