我有以下脚本,它将根据文件“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_S
和YES
永远无法匹配。
您可以通过转换器传递文件,或者更简单地忽略最后一个字段末尾的尾随字符:
case "$f7" in
NOT_S*) ... ;;
YES*) ... ;;
esac