bash - 将“表”值分隔成数组中的字符串

bash - 将“表”值分隔成数组中的字符串

编辑:对不起,我声称的输出是错误的。空格比我之前想象的要多(当输出保存到html文件以删除这些空格时发生了一些事情)真正的输出如下:

user@Debian:~$ sudo smartctl -l selftest /dev/sda | grep -e "#"
# 1  Short offline       Completed without error       00%      7264         -
# 2  Short offline       Completed without error       00%      7240         -
# 3  Short offline       Completed without error       00%      7219         -
# 4  Short offline       Completed without error       00%      7192         -
# 5  Short offline       Completed without error       00%      7168         -
# 6  Short offline       Completed without error       00%      7144         -
# 7  Extended offline    Completed without error       00%      7125         -
# 8  Short offline       Completed without error       00%      7096         -
# 9  Short offline       Completed without error       00%      7072         -
#10  Short offline       Completed without error       00%      7049         -
#11  Short offline       Completed without error       00%      7004         -

我不确定我是否使用了正确的术语,因为我对 Linux/bash 相当陌生。

不管怎样,我正在使用 Smartmontools 来检测并通知我是否有任何 SMART 错误。它按照我想要的方式工作,但我想获得有关 HDD 的一些日常统计信息,因此我制作了自己的脚本,从 smartmontools 和其他有趣的东西(如临时、SMART 值和使用的 HDD 空间)收集信息。可能不是做这样的事情的最好方法,但我喜欢这样做,并且我正在边做边学。

我发送的电子邮件采用 HTML 格式来制作表格并添加正面/负面结果的字体颜色(绿色/红色)。但当我尝试制作一张用于显示自测试的表格时,我遇到了一些问题。

我使用的命令是:(sudo smartctl -l selftest $HDD | grep '#' >> $SMARTFILE在一个循环中,$HDD 是我系统中的所有 HDD,$SMARTFILE 是我将其保存到的 html 文件。

该命令的输出如下所示:

# 1 短暂离线 已完成且没有错误 00% 7264 -

# 2 短暂离线 已完成且无错误 00% 7240 -

等等。我使用以下代码来获取驱动器的序列号:

HDDinfo="$(sudo smartctl --info $HDD | grep -e 'Serial Number')"
IFS=':' read -r -a array <<< "$HDDinfo"

由于sudo smartctl --info $HDD | grep -e 'Serial Number'通常输出

序列号:WD-RESTOFS/N123

但为了将其放入表中,我使用“:”字符分隔字符串并获得如下数组:

序列号,WD-RESTOFS/N123

但是对于我得到的输出sudo smartctl -l selftest $HDD | grep '#' >> $SMARTFILE,(对我来说)没有明显的方法来分隔它们,而且我之前所做的方式不起作用,因为我想要的字符串中有空格,因此不能使用空格字符分隔。

TL;DR,我有以下命令sudo smartctl -l selftest /dev/sda | grep '#' >> $SMARTFILE,其输出如下:

# 1 短暂离线 已完成且没有错误 00% 7264 -

# 2 短暂离线 已完成且无错误 00% 7240 -

我想创建一个数组(或类似的数组)来单独存储它们,如下所示:

# 1,短暂离线,完成无错误,00%,7264,-

这样我就可以轻松地将其放入 HTML 表格中。这可以做到吗?如果确实发生错误,它可能看起来像这样:

#1 短离线完成:读取失败20% 717 555027747

如果有不清楚的地方或需要任何其他信息,请告诉我。

答案1

从上面的(小)smartctl消息样本来看,它们的各个部分似乎基本上是由“<空格><除小写之外的任何内容>”分隔的(除了行开头的“# nnn”字段)。

sed可以帮助分离零件:

$ smartctl_output="\                                           
# 1 Short offline Completed without error 00% 7264 -
# 2 Short offline Completed without error 00% 7240 -
# 1 Short offline Completed: read failure 20% 717 555027747"

$ csv="$( sed 's/ //; s/ \([^[:lower:]]\)/,\1/g' <<< "$smartctl_output" )"

$ echo "$csv"
#1,Short offline,Completed without error,00%,7264,-
#2,Short offline,Completed without error,00%,7240,-
#1,Short offline,Completed: read failure,20%,717,555027747

如果这是您想要的,您现在可以像使用 HDDinfo 一样填充阵列。

[更新]

sed这是对进行拆分的部分的解释:该sed程序由我放在一行上的两部分组成。这是扩展版本:

sed '
    s/ //
    s/ \([^[:lower:]]\)/,\1/g
'

程序sed对每一行输入进行操作:它读取一行,应用一组转换,然后打印该行。然后它从下一行开始,直到没有更多的行可供读取。

这里第一个sed命令s/ //删除第一个空格以将“#”和后面的数字放在一起。

然后,第二个sed命令s/ \([^[:lower:]]\)/,\1/g搜索每个字段的开头(由“<空格><小写字母以外的任何内容>”定义)并用冒号替换空格。指\1的是括号“ ”之间的正则表达式\([^[:lower:]]\),它代表下一个字段的第一个字符。

剩下的部分是一个测试:sed我没有输入文件的内容或命令的输出,而是输入了变量smartctl_output(由样本组成的字符串),并将结果分配给了该csv变量。

[更新#2]

现在看来,这些字段是由两个或多个空格分隔的。它甚至比以前更容易。命令sed变为:

sed 's/  \+/,/g'

这意味着:用冒号替换所有两个或多个空格的系列。

答案2

我想不出一种方法可以在 shell 中本地执行此操作,但是perl例如您可以定义一个正则表达式用于字段分割,并使用它插入您选择的单个分隔符,然后可以简单地使用IFS=,或其他方式读取该分隔符。

根据您的示例,字段可能会按空格分割,后跟以下任一内容:

  1. 大写字符或连字符;或者
  2. 至少两个数字的序列

所以通过管道传递你的命令

. . . | 
  perl -F'[[:space:]](?=[[:upper:]-]|[[:digit:]]{2,})' -anle 'print join ",", @F'

相关内容