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 Forms에서 생성되었으며 wget을 통해 Google Sheets에서 응답을 다운로드하고 있습니다. 현재 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 Forms를 사용하여 가상 워크스테이션에서 시간을 예약합니다. 양식은 자동으로 이메일 주소를 검색합니다. 테이블은 이메일 주소를 기반으로 학생과 연결된 워크스테이션 이름으로 채워집니다. 그런 다음 양식에서는 워크스테이션에 얼마나 많은 시간을 머물기를 원하는지 묻습니다. 드롭다운 메뉴에서 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]$ 

두 번째 편집:

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

입력 파일에는 유닉스 개행 문자(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: 헤더 및 주석 우회에 대한 주석 후 스크립트 변경(및 $i의 이유)

답변2

언제나처럼다른 곳에서 설명, 파일의 줄은 Windows 스타일 CRLF 끝으로 끝납니다. 즉, 마지막 필드는 항상 CR 문자로 끝나므로 리터럴 NOT_SYES일치하지 않습니다.

변환기를 통해 파일을 전달하거나 마지막 필드 끝에 있는 후행 문자를 간단히 무시할 수 있습니다.

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

관련 정보