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シートからレスポンスをダウンロードしています。現在、Googleスプレッドシートの$ 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時間を選択できます。完了すると、フォームは入力内容をGoogleスプレッドシートに保存します。

ワークシートには、タイムスタンプ時間+ 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]$ 

2番目の編集:

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:

Olivierの修正はうまくいきます。しかし、他の問題を解決する必要がありますが、皆さんが私を助けてくれることを願っています。したがって、Googleシートには、要求されたアイテムのタイムスタンプ+ 10分を確認してタイムアウトしたことを確認するGoogleフォームからの応答を収集し、その場合はフラグをYESに変更する式が>=ありますnow()。さて、フォームではうまく機能し、フラグが変更されましたが、私のcronジョブがファイルの次のwgetを取得したときにf7フィールドの変更が認識されず、エントリがまだNOT_Sなので、私のスクリプトScheduled jobsは引き続き予定されています.

私が最終的に望むのは、ジョブがスケジュールされるとすぐにフラグを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の前に。
  • 最後のエコーを削除します。 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:ヘッダーとコメントをバイパスするためのコメント後のスクリプトの変更

おすすめ記事