【问题标题】:Bash: Use variable in loopBash:在循环中使用变量
【发布时间】:2017-06-15 23:33:17
【问题描述】:

在你们上次出色地帮助了我之后,我(再次)需要一些帮助。 我正在编写一个脚本来使用 SmartCTL 测试我的硬盘驱动器。所以我当然可以复制每个磁盘的命令,但是如果我可以只设置一次磁盘并且脚本会一一执行,那就更棒了:

#!/bin/bash
 date=`date +%d-%m-%Y-%T`
 touch /var/log/disk/Disk-health-check-$date
 disks="/dev/sda 
 /dev/sdb"
 for disk in disks
    do
    wait=$(smartctl -t short $disk | awk '/Please wait/ {print $3}')
      echo "waiting..."
      sleep $((wait * 60 + 60))
      echo "done"
      smartctl --log=selftest $disk
      smartctl -a $disk
   done
 exit

但不幸的是它只使用/dev/sda,而不是sdb等。 那么我怎样才能使它起作用呢?提前谢谢大家!!

【问题讨论】:

  • for disk in $disks,而不是for disk in disks。虽然即使这样也是不好的做法。
  • disks=( /dev/sda /dev/sdb ),并使用for disk in "${disks[@]}",作为数组。并修复shellcheck.net 发现的所有错误。
  • 另外——使用YYYY-mm-dd 作为您的日期格式。它是一个 ISO 标准,而且 - 更重要的是 - 它的 ASCII 排序顺序与其作为日期的排序顺序一致,这对于您在此处尝试使用的格式绝对不正确。正确的 ASCII 排序顺序可以更容易地找到最旧或最新的文件,或者每个比特定日期更早的文件,等等。

标签: linux bash shell disk


【解决方案1】:

试试这个:

for disk in disks; do
  echo "$disk"
done

您会看到它唯一回显的是disks。那是因为你告诉它只迭代一个值,那个值是disks


要执行您想要做的微妙错误的事情,您想要:

for disk in $disks; do
  echo "$disk"
done

但是,正如我所说,那是 buggy。假设您的 disks 变量的分配方式有所不同:

disks='
/dev/disks/by-label/My Drive
/dev/disks/by-label/Other Drive
/dev/disks/by-label/* TEENAGE DAUGHTER'S DRIVE *
'

这会将/dev/disks/by-label/My 作为一个条目,Drive 作为下一个条目——当您运行脚本时,*s 将扩展为您所在目录中的文件名。显然不是你想要的。

改为使用数组:

disks=(
  "/dev/disks/by-label/My Drive"
  "/dev/disks/by-label/Other Drive"
  "/dev/disks/by-label/* TEENAGE DAUGHTER'S DRIVE *"
)

...并将它们迭代为:

for disk in "${disks[@]}"; do
  echo "Processing: $disk"
done

【讨论】:

  • 谢谢,太好了。你介意解释一下“${disks[@]}”它是如何工作的吗?老实说,我以前从未见过这种情况。使用 ("disks disk") 或 disks=(disk1 disk2) 有什么区别吗? (你和查克·多纳休的)?
  • 我的答案和查克的答案实际上是等效的,因为手头的内容不需要被引用。在名称不包含任何空格或全局字符的情况下,disks=( "/dev/sda" "/dev/sdb" ) 也可以使用。我展示了上面的引用来演示它在需要数组时如何工作,而它不会disks='"/dev/sda" "/dev/sdb"' 或类似的一起工作;有关故障模式的详细讨论,请参见 BashFAQ #50
  • 至于"${disks[@]}",这是标准的数组扩展语法——请参阅BashFAQ #5,或从 Chuck 的答案链接的数组上的 bash-hackers wiki 页面。
【解决方案2】:

试试这个:

#!/bin/bash
date=$(date +%d-%m-%Y-%T)
touch /var/log/disk/Disk-health-check-"$date"
disks=(/dev/sda /dev/sdb)
for disk in "${disks[@]}"
   do
   wait=$(smartctl -t short "$disk" | awk '/Please wait/ {print $3}')
     echo "waiting..."
     sleep $((wait * 60 + 60))
     echo "done"
     smartctl --log=selftest "$disk"
     smartctl -a "$disk"
  done
exit

基于此处列出的数组变量: http://wiki.bash-hackers.org/syntax/arrays?s[]=arrays

【讨论】:

  • 好多了。我建议将日志定向到 stderr 而不是 stdout——因为它们是状态(用于用户消费)而不是输出(发送到管道中的下一个程序)——但这里没有任何问题.
  • 感谢您提供到 spellcheck.net 的链接
  • err,它是“shellcheck”,带有 h 而不是 p :)
猜你喜欢
  • 2020-10-20
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
  • 2022-01-04
  • 2014-01-07
  • 1970-01-01
  • 2020-09-12
  • 1970-01-01
相关资源
最近更新 更多