使用 case 语句做出决定时,Bash 脚本不起作用

使用 case 语句做出决定时,Bash 脚本不起作用

我有以下脚本,它将根据文件“schedule.csv”的输入来安排作业。该文件包含 7 个字段,$f7 字段包含一个标志,对于需要计划的作业,该标志为“NOT_S”;如果该作业已被计划,则为“YES”。

#!/bin/bash
filename='/home/opc/3A-Lab/schedule.csv'

i=1
while IFS=, read -r f1 f2 f3 f4 f5 f6 f7; do

        case "$f7" in

        NOT_S)
                test  $i -eq 1 && ((i=i+1)) && continue
                echo "/home/opc/3A-Lab/3ALab.sh $f5 start" | at  now
                echo "/home/opc/3A-Lab/3ALab.sh $f5 stop"  | at  now + "$f6" " " "hours"
                ;;
        YES)
                echo "Already Scheduled"
                ;;
esac
done < $filename

echo "something is wrong"

当我运行脚本时,我得到“出了问题”的输出,这是我添加的故障排除步骤,以提醒我由于某种原因我的逻辑无法正常工作。

我想要的是要调度具有“NOT_S”标志的作业,以及要忽略具有“YES”标志的作业。如果没有决策逻辑,作业将根据需要进行安排。然而,这样做的问题是,一旦脚本再次运行,我就无法排除已经安排的作业。它正在读取的文件是由 Google 表单生成的,我正在通过 wget 从 Google Sheets 下载响应。我目前让 Google Sheets 在 $f7 列中设置标志,以便在一段时间后,当再次下载文件并在服务器上再次运行脚本时,它只会处理已添加到工作表中的作业有“NOT_S”标志并忽略其他标志。

我在脚本中做错了什么,为什么它没有获取 $f7 的值并执行命令来安排作业?感谢您的任何帮助,您可以提供。

编辑:

以下是该schedule.csv文件的示例:

Timestamp,Email Address,First Name,Last Name,Workstation Name,Duration (in hours),Schedule Flag
,,,,no workstation,,YES
1/1/2021 14:52:11,[email protected],Jone Doe,no workstation,2,NOT_S
1/1/2021 15:39:48,[email protected],jane,sue,no workstation,2,NOT_S
1/1/2021 15:40:26,fred.flintstone,Fred,Flintsone,no workstation,5,YES
,,,,no workstation,,YES
,,,,no workstation,,
,,,,no workstation,,

让我解释一下该文件:一名学生使用 Google 表单预订虚拟工作站的时间。该表单会自动检索他们的电子邮件地址。根据他们的电子邮件地址,该表将填充与学生关联的工作站名称。然后表格会询问他们想要在工作站上保留多少时间。他们可以从下拉菜单中选择 1 到 5 小时。完成后,表单会将他们的输入保存到谷歌表格中。

该工作表有一个公式,该公式将确定使用时间戳时间 +10 分钟将字段 7 中的标志设置为 NOT_S 或 YES。 10 分钟结束后,标志将设置为 YES。在调度时,它被设置为 NOT_S。

以下是不带条件逻辑的调度作业的脚本的示例输出:

job 13984 at Sat Jan  2 14:41:00 2021
syntax error. Last token seen: hours
Garbled time
job 13985 at Sat Jan  2 14:41:00 2021
job 13986 at Sat Jan  2 16:41:00 2021
job 13987 at Sat Jan  2 14:41:00 2021
job 13988 at Sat Jan  2 16:41:00 2021
job 13989 at Sat Jan  2 14:41:00 2021
job 13990 at Sat Jan  2 19:41:00 2021
job 13991 at Sat Jan  2 14:41:00 2021
syntax error. Last token seen: hours
Garbled time
job 13992 at Sat Jan  2 14:41:00 2021
syntax error. Last token seen: hours
Garbled time
[opc@vm-control-server 3A-Lab]$ 

第二次编辑:

以下是使用 Gordon 建议的命令的输出:

[opc@vm-control-server 3A-Lab]$ file ./schedule.csv 
./schedule.csv: ASCII text, with CRLF line terminators
[opc@vm-control-server 3A-Lab]$ LC_ALL=C cat -vet ./schedule.csv 
Timestamp,Email Address,First Name,Last Name,Workstation Name,Duration (in hours),Schedule Flag^M$
,,,,no workstation,,YES^M$
1/1/2021 14:52:11,[email protected],Philip,Monroe,no workstation,2,NOT_S^M$
1/1/2021 15:39:48,[email protected],John,Crocket,no workstation,2,NOT_S^M$
1/1/2021 15:40:26,[email protected],Eddie,Reed,no workstation,5,YES^M$
,,,,no workstation,,YES^M$
,,,,no workstation,,^M$
,,,,no workstation,,[opc@vm-control-server 3A-Lab]$ 

编辑3:

这是我正在运行脚本的更新文件:

[opc@vm-control-server 3A-Lab]$ LC_ALL=C cat -vet ./schedule.csv 
Timestamp,Email Address,First Name,Last Name,Workstation Name,Duration (in hours),Schedule Flag^M$
,,,,no workstation,,YES^M$
1/1/2021 14:52:11,[email protected],Philip,Monroe,no workstation,2,NOT_S^M$
1/1/2021 15:39:48,[email protected],John,Crocket,no workstation,2,NOT_S^M$
1/1/2021 15:40:26,[email protected],Fred,Brown,no workstation,5,YES^M$
,,,,no workstation,,YES^M$
,,,,no workstation,,^M$
,,,,no workstation,,[opc@vm-control-server 3A-Lab]$ 

脚本的输出。请记住,此运行没有任何决策逻辑,因此它没有考虑 f7 字段,因此它会安排工作表上的所有作业。

[opc@vm-control-server 3A-Lab]$ ./final2.sh
job 13993 at Sat Jan  2 15:38:00 2021
syntax error. Last token seen: hours
Garbled time
job 13994 at Sat Jan  2 15:38:00 2021
job 13995 at Sat Jan  2 17:38:00 2021
job 13996 at Sat Jan  2 15:38:00 2021
job 13997 at Sat Jan  2 17:38:00 2021
job 13998 at Sat Jan  2 15:38:00 2021
job 13999 at Sat Jan  2 20:38:00 2021
job 14000 at Sat Jan  2 15:38:00 2021
syntax error. Last token seen: hours
Garbled time
job 14001 at Sat Jan  2 15:38:00 2021
syntax error. Last token seen: hours
Garbled time
[opc@vm-control-server 3A-Lab]$ 

编辑4:

奥利维尔的修改效果很好。但是,我需要解决另一个问题,希望大家能够帮助我。因此,我正在收集来自 google 表单的响应的 google 工作表上有一个公式,该公式检查所请求条目的时间戳 + 10 分钟,以查看是否到>=now(),如果是,则将标志更改为 YES。嗯,它在表单上工作得很好,并且标志被更改,但是,当我的 cron 作业拉取文件的下一个 wget 时,它无法识别 f7 字段的更改,并且条目仍然为 NOT_S,因此我的脚本将继续安排已安排的作业。

我最终想做的是一旦安排了作业,立即将标志设置为 YES,这样一旦文件再次被读取,它将被忽略。

我试图弄清楚如何使用 wget 只提取对工作表文件的更改,而不必每次都下载整个内容。我想设置一些东西,我可以将其写入 Linux 服务器上的本地文件,然后让脚本使用标志更改更新该本地文件,并且只从 google 工作表中获取新条目。我希望得到一些帮助。谢谢。

答案1

您的输入文件在 unix 换行符 (lf) 之前有 ^M (cr) 字符。因此,您的 f7 字段不是预期的。

传递文件通过:dos2unix <oldfile>newfile

或:tr -d '\015' <旧文件> 新文件

然后再试一次。

还要确保:

  • 所有输入行都有 7 个参数(空或非空,即有 6 个逗号):awk -F',' '(NF != 7) { print "line: " NR " has " NF " arguments : " $0 }' /home/opc/3A-Lab/schedule.csv
  • 为您的情况添加默认行,以通知哪些行不对应于任一情况:*) printf "Something is wrong: We have a line with an unexpected f7='%s'\n" "$f7" ;; # 在 esac 之前。
  • 删除最后一个 echo :无论 while 做什么,它都会始终显示。或者只是将其修改为:echo "End of the script."
  • 带有小时的行有一个额外的空参数:更改at now + "$f6" " " "hours"at now + "$f6" hours

所以脚本变成:

#!/bin/bash
filename='/home/opc/3A-Lab/schedule.csv'

i=0
while IFS=, read -r f1 f2 f3 f4 f5 f6 f7; do
    i=$(( i + 1 ))
    if [ "$i" = "1" ]; then printf "Bypass first line\n" ; continue ; fi
    if [ -z "$f1" ]; then printf "Bypass line: %s, empty field f1\n" "$i" ; continue ; fi
    case "$f7" in
    NOT_S)
            printf "/home/opc/3A-Lab/3ALab.sh %s start\n" "$f5" | at  now
            printf "/home/opc/3A-Lab/3ALab.sh %s stop\n"  "$f5" | at  now + "$f6" hours
            printf "scheduled start and stop for line: %s\n" "$i"
            ;;
    YES)
            printf "line %s: YES : Already Scheduled\n" "%i"
            ;;
    "")     printf "Warning: I see an empty f7... for line: %s =  '%s,%s,%s,%s,%s,%s,%s'\n" "$i" "$f1" "$f2" "$f3" "$f4" "$f5" "$f6" "$f7"
            ;;
    *)
            printf "Something is wrong: line %s: we see f7='%s'\n No action taken.\n" "$i" "$f7"
            ;;
    esac
done < $filename

printf "End of the Script.\n"

我也很困惑为什么你不想对遇到的第一个 NOT_S 行(即 i=1)做任何事情......但你可能有你的理由。

edit1:将 echo 更改为 printf ,这是一个好习惯(printf 是可移植的,echo 不是。) edit2:更改了有关绕过标题和注释的注释后的脚本(以及 $i 的原因)

答案2

一如既往在别处解释过,文件的行以 Windows 样式的 CRLF 结尾结束。这意味着您的最后一个字段始终以 CR 字符结尾,因此您的文字NOT_SYES永远无法匹配。

您可以通过转换器传递文件,或者更简单地忽略最后一个字段末尾的尾随字符:

case "$f7" in
    NOT_S*) ... ;;
    YES*) ... ;;
esac

相关内容