파일에 특정 데이터가 포함되어 있는지 확인하기 위해 함수를 호출할 수 있는 bash 스크립트가 필요하며, 그렇지 않은 경우 기본 스크립트가 실패합니다. 이는 이를 유지하기 위해 단순화된 아래와 유사합니다.
이것은 작동하지 않습니다(하위 쉘이 실패하면 기본 스크립트가 종료되지 않습니다).
require_line
아래와 같이 한 파일에 20개 이상의 함수를 말할 수 있게 하려면 이 함수를 어떻게 작성해야 할까요?
VALUE1=$(require_line "myKey1")
VALUE2=$(require_line "myKey2")
...
그리고 각각 주위에 if가 필요하지 않습니까?
#!/bin/bash
set -eo pipefail
VALUE=$(require_line "myKey")
require_line(){
local KEY=$1
local DATA=$(cat /tmp/myfile)
local INFO=$(echo "$DATA" | grep "$KEY")
if [ ! -z "$INFO" ]
then
echo "Key not found in $DATA, key: $KEY"
exit 1;
fi
echo "$INFO"
}
답변1
하위 쉘을 종료해도 경험한 것처럼 기본 스크립트가 종료되지 않습니다.
나는 3가지(절반) 해결책을 생각했습니다.
- ("테스트되지 않은") 실패한 명령(또는 하위 쉘)이 기본 스크립트를 즉시 종료하도록 하려면 이를 사용하십시오
set -e
(과도하거나 다른 문제를 일으킬 수 있음). - 함수에서 신호를 보내고
trap
|| exit $?
매번 사용할 때마다VALUEn=$(...)
이런 느낌이에요VALUE=$(require_line "myKey") || exit $?
,- .을 사용하여 (3.)을 (덜 우아한) 루프와 결합합니다
eval
.
세 번째는 정확히 "각각 주위에 if가 필요"하지 않으며 여전히 매우 컴팩트한 구문 IMHO입니다.
덧붙여서, 이 줄
echo "Key not found in $DATA, key: $KEY"
$VALUEn
...이 직후에 전체 스크립트를 종료하면 문장이 표시되지 않는 변수 에 저장되므로 사실상 쓸모가 없습니다 .
다음과 같이 인쇄하는 것이 좋습니다 stderr
.
echo "my error" 1>&2
예
솔루션 1의 예
#!/bin/sh
set -e
myfunc(){
echo $1
if [ "$1" != "OK" ] ; then exit 1 ; fi
}
VALUE1=$(myfunc "OK")
echo $VALUE1
VALUE2=$(myfunc "NO WAY")
echo $VALUE2
echo "main script did not exit"
$ ./test.sh
OK
zsh: exit 1 ./test.sh
하지만 set -e
처음부터 삭제하면 다음과 같은 결과가 나타납니다.
$ ./test.sh
OK
NO WAY
main script did not exit
솔루션 2의 예
#!/bin/sh
trap "exit $?" USR1
myfunc(){
echo $1
if [ "$1" != "OK" ] ; then kill -USR1 $$ ; fi
}
VALUE1=$(myfunc "OK")
echo $VALUE1
VALUE2=$(myfunc "NO WAY")
echo $VALUE2
echo "main script did not exit"
$ ./test.sh
OK
솔루션 3의 예
#!/bin/sh
myfunc(){
echo $1
if [ "$1" != "OK" ] ; then exit 1 ; fi
}
VALUE1=$(myfunc "OK") || exit $?
echo $VALUE1
VALUE2=$(myfunc "NO WAY") || exit $?
echo $VALUE2
echo "main script did not exit"
$ ./test.sh
OK
zsh: exit 1 ./test.sh
솔루션 4의 예
#!/bin/sh
myfunc(){
echo $1
if [ "$1" != "OK" ] ; then exit 1 ; fi
}
I=1
for key in "OK" "OK" "NO WAY": ; do
eval "VALUE$I=\$(myfunc \"$key\")" || exit $?
eval "echo \$VALUE$I"
I=$(($I+1))
done
echo "main script did not exit"
$ ./test.sh
OK
OK
zsh: exit 1 ./test.sh
답변2
require_line
도움이 되도록 스크립트를 조금 리팩터링 해 보겠습니다 .
첫째, 쓸모없는 것들을 제거할 수 있습니다 cat | grep
. 둘째,
grep
본질적인 동작을 사용하여 검색의 성공 또는 실패를 나타낼 수 KEY
있을 뿐만 아니라 키(발견된 경우)를 에 인쇄할 수 있습니다 stdout
.
require_line(){
local KEY="$1"
local FILE="/tmp/myfile"
if grep "$KEY" "$FILE"
then
return 0
else
printf 'Key not found in:\n\n"%s"\n\nKey: "%s"\n' "$(cat "$FILE")" "$KEY" >&2
return 1
fi
}
이는 의 내장 동작을 활용합니다 grep
. 키가 발견되면 grep
일치하는 줄을 인쇄하고 성공을 반환합니다. 그렇지 않으면 분기가 수행 else
되고 키를 찾을 수 없다는 메시지가 인쇄됩니다. 또한 오류가 발생한 경우 오류 메시지 가 에서 발견된 유효한 일치 항목으로 오인되지 않도록 grep
오류 메시지가 에 인쇄됩니다 .stderr
$FILE
읽을 행을 변경한 다음 각 호출에서 원하는 파일 이름을 전달하여 require_line
파일 이름을 인수로 허용하도록 추가로 수정할 수 있습니다 .$2
local FILE="$2"
require_line
이제 이걸로...
KEYn의 모든 VALUEn을 실제로 저장해야 합니까, 아니면 모두 존재하는지 확인해야 합니까?
require_line
이제 성공 또는 실패 값을 명확하게 반환하는 함수가 있으므로 AND
모든 테스트를 간단히 통합할 수 있습니다. 그 중 하나라도 실패하면 전체 테스트가 실패합니다.
실제 일치 값이 실제로 필요하다고 가정하면 자세한 접근 방식은 다음과 같습니다.
if value1=$(require_line "key1") &&
value2=$(require_line "key2") &&
value3=$(require_line "key3")
then
printf "%s\n" "$value1" "$value2" "$value3"
else
printf "One or more keys failed.\n" >&2
fi
확인해야 할 키가 많으면 지루해질 수 있습니다. 배열을 사용하는 것이 더 나을 수도 있습니다.
#!/usr/bin/env bash
require_line(){
local KEY="$1"
local FILE="/tmp/myfile" # or perhaps "$2"
if grep "$KEY" "$FILE"
then
return 0
else
printf 'Key not found in:\n\n"%s"\n\nKey: "%s"\n' "$(cat "$FILE")" "$KEY" >&2
return 1
fi
}
declare keys=("this" "is" "a" "test" "\." "keyN")
N=${#keys[@]}
declare values=()
j=0
while [ $j -lt $N ] && values[$j]="$(require_line "${keys[j]}")"
do
j=$(($j+1))
done
if [ $j -lt $N ]
then
printf 'error: found only %d keys out of %d:\n' $j $N
printf ' "%s"\n' "${values[@]}"
fi
일부 샘플 데이터를 사용하여 코드를 실행합니다.
$ cat /tmp/myfile
this is a test.
$ ./test.sh
Key not found in:
"this is a test."
Key: "keyN"
error: found only 5 keys out of 6:
"this is a test."
"this is a test."
"this is a test."
"this is a test."
"this is a test."
""
마지막으로, 실제로 모든 키가 존재하는지 확인해야 하고 일치하는 값이 무엇인지 알 필요가 없다면 위의 배열 지향 코드를 모든 키를 찾을 때까지 단순히 반복하거나 중지하는 것으로 줄일 수 있습니다. 첫 번째 키에서 누락된 것이 발견되었습니다.