저는 쉘 스크립팅을 처음 접했고 기본 사항을 배우려고 노력하고 있습니다. "./scriptgoeshere.sh Argument1 Argument2"와 같은 터미널을 사용하여 스크립트를 시작합니다.
스크립트에서 에코를 인쇄하고 싶습니다. "Hello World"가 사용하기에 가장 적합할 것입니다. 하지만 다음과 같은 경우에만 hello world를 인쇄하고 싶습니다. 인수가 정확히 두 개이고 해당 인수는 숫자로만 구성되어야 합니다. 예를 들어:
./scriptgoeshere.sh 1523 9643 ./scriptgoeshere.sh 7 96 그러나 작동해야 합니다. ./scriptgoeshere.sh 594 arg 작동하지 않아야 합니다. 이것은 현재 제가 가지고 있는 스크립트이지만 작동하지 않습니다. 하루 종일 이것을 알아내려고 노력했지만 제대로 이해하지 못하는 것 같습니다. if/elif/else도 시도해 보았습니다. 계속하기 전에 if 부분에 2개의 입력이 있는지, 그리고 둘 다 elif에 숫자인지 확인했습니다.
#!/bin/bash
if [ "$#" -eq 2 ] && [ "$@" -eq ^[0-9] ];
then
i=0
while [ $i -lt 3 ]
do
echo "Hello World!"
sleep 5
i=$((i+1))
done
else
echo "Need two arguments and only numbers will be accepted, such as ./scriptgoeshere 153 251"
fi
2개의 인수를 입력할 때까지 hello world 루프를 차단하지만 숫자인지 텍스트인지는 중요하지 않으며 다음 오류가 발생합니다. "./scriptgoeshere.sh: line 2: [: ^[0-9]: 정수 표현식이 필요합니다." 터미널에 ./scriptgoeshere.sh 123 123을 작성하여 실행해도 해당 오류가 발생합니다. 실제 스크립트를 시작할 때 인수를 파악하고 싶기 때문에 변수로 해결하지 않는 것을 선호합니다.
이게 내 머리를 짓밟고있어!
이것이 정확히 2개의 인수가 있고 작동하는지 확인하기 위해 시작한 작업입니다. 2개의 인수가 숫자가 되도록 작은 수정 사항을 추가하고 싶습니다. 왜 그렇게 힘든지 모르겠습니다.
#!/bin/bash
if [ "$#" -eq 2 ];
then
i=0
while [ $i -lt 3 ]
do
echo "Hello World!"
sleep 1
i=$((i+1))
done
else
echo "Need two argument, only numbers accepted"
fi
편집 : 해결했습니다. 나는 너무 가깝게 일했습니다.. if-문자열의 숫자 부분에 []를 추가하면 됩니다. 첫 번째 부분은 하나만 [] 으로 쓸 수 있는데 왜 [[ "$@" -eq ^[0-9] ]] 로 써야 하는지 아는 사람이 있나요?
답변1
처음에는 [ "$#" -eq ^[0-9] ]
또는 [ "$@" -eq ^[0-9] ]
(답변을 작성하는 동안 질문이 편집되었습니다…). 문맥상 매개변수가 숫자인지 테스트하고 싶다고 생각합니다.
$#
는 항상 숫자이며 십진수로 된 위치 매개변수의 수입니다. 두 개의 위치 매개변수$1
인 및 를 테스트하려고 합니다$2
.[
은 명령입니다([ whatever ]
와 동일test whatever
). 쉘 내장일 수도 있지만 구문론적으로는ls
또는 와 같습니다man
. 뒤에 오는 단어( 포함]
)는 명령 뒤에 오는 다른 단어와 마찬가지로 쉘에 의해 구문 분석됩니다. 쉘은 해당 단어를 확장하고(예:$#
숫자가 됨) 따옴표를 제거합니다. 결국 그들은 에 대한 매개변수가 됩니다[
. 이러한 확장 중 하나는 다양한 패턴이 기존 파일 이름과 일치하는 파일 이름 확장(파일 이름 확장, 글로빙)입니다. 인용되지 않은 파일은 이러한 파일이 존재하는 경우^[0-9]
확장될 수 있습니다 .^2 ^5
일치하는 항목이 없거나 비활성화하면 기능이 문자 그대로 (인수 중 하나로)^[0-9]
표시됩니다 .[
패턴처럼 보이지만[
어쨌든 패턴 일치를 지원하지 않습니다.-eq
이전 인수와 다음 인수는 정수여야 합니다.$#
확실히 정수로 확장됩니다.^[0-9]
이 컨텍스트에서는 숫자로 확장할 수 있는 방법이 없습니다 .큰따옴표는
$@
특별합니다. 인용되었음에도 불구하고 여러 단어(POSIX의 경우 "필드")로 확장될 수 있습니다. 일반적으로 단어 분할을 방지하기 위해 인용합니다."$foo"
값에 공백 등이 포함되어 있어도 한 단어로 확장됩니다."$@"
처럼 확장되면"$1" "$2" …
큰따옴표로 인해$1
여러 단어로 확장되는 것이 방지됩니다(별도로$2
등등). 이 단편에서는:[ "$#" -eq 2 ] && [ "$@" -eq ^[0-9] ]
두 번째는
[
첫 번째가 성공하면 실행됩니다(이것이&&
작동 방식입니다). 즉, 정확히 두 개의 위치 매개변수가 있는 경우입니다. 그러한 경우에는"$@"
와 동일하며"$1" "$2"
두 번째 테스트는 다음과 같습니다.[ "$1" "$2" -eq ^[0-9] ]
이것은 말이 되지 않습니다.
[
매개변수의 실제 값과 확장에 따라 다른 방식으로 불평할 수 있지만^[0-9]
여전히 쓰레기입니다.
이제 약 [[ "$#" = [0-9] ]]
.
참고: 이 스니펫은 질문의 첫 번째 개정판에 있었습니다. 답변을 작성하는 동안 질문이 편집되었습니다. [[
어쨌든 결국에는 유용할 수 있기 때문에 이 조각을 유지하기로 결정했습니다 .
- 다시 말하지만
$#
항상 숫자입니다. [[
와 동일하지 않습니다[
. 당신이 할 수 있는 모든 정상 테스트는[
으로 다시 작성할 수 있습니다[[
(그러나 무심코[
로 대체하여 이 작업을 수행해서는 안 되지만[[
). 추가 테스트를[[
수행할 수 있으며 더 강력합니다.[
(및test
)은 POSIX에서 필요 하지만[[
그렇지 않습니다.중요한 점: 또는
[[
과 같은 명령이 아닙니다 . 이는 키워드이며 쉘이 뒤따르는 단어를 구문 분석하는 방식을 변경합니다. 와 사이의 모든 내용은 다르게 구문 분석됩니다.ls
[
[[
]]
연산자가 인 경우
=
다음 인수는 패턴입니다. 일부 문자/구문(예:*
또는[0-9]
)은 따옴표가 없으면 이전 인수와 일치합니다=
. 파일 이름 확장과 비슷하지만 기존 파일 이름에 대한 확장은 아닙니다. (확장)이$#
정확히 한 자리 인지 테스트한 코드 입니다. 전체 테스트는 다음과 같았습니다.[[ "$#" -eq 2 ]] && [[ "$#" = [0-9] ]]
foo && bar
bar
성공 하면 실행됩니다foo
. 두 번째는 으로 확장된[[
경우에만 테스트되었으므로 정확히 한 자리이기 때문에 성공해야 했습니다 . 이 경우 두 번째는 아무것도 변경하지 않습니다.$#
2
2
[[
실수를 깨닫고 $1
숫자인지 테스트했다고 가정해 보겠습니다.
- 위와 같이 정확히 한 자리로 확장
[[ "$1" = [0-9] ]]
되면 성공을 반환합니다 .$1
[[ "$1" = [0-9][0-9] ]]
– 정확히 두 자리 숫자입니다.[[ "$1" = [0-9]* ]]
– 숫자로 시작하는 것.
필요한 자릿수를 감지하려면 =~
. 내부의 이 연산자 [[ ]]
는 와 다소 유사 =
하지만 이제 패턴은 확장된 정규식입니다. 전체 문자열을 연산자 왼쪽과 일치시킬 필요는 없지만 하위 문자열이면 충분합니다(따라서 귀하의 경우 앵커가 필요합니다) ^
.$
[[ "$1" =~ [0-9] ]]
$1
숫자가 포함된 문자열로 확장 되면 성공을 반환합니다 .[[ "$1" =~ [0-9][0-9] ]]
– … 두 자리 숫자가 나란히 포함되어 있습니다.[[ "$1" =~ ^[0-9]$ ]]
– 정확히 한 자리의 문자열입니다.[[ "$1" =~ ^[0-9]*$ ]]
– 0개 이상의 숫자.[[ "$1" =~ ^[0-9][0-9]*$ ]]
– 하나 이상의 숫자.[[ "$1" =~ ^[0-9]+$ ]]
– 하나 이상의 숫자.
[[ "$1" =~ ^[0-9]+$ ]]
그리고 [[ "$2" =~ ^[0-9]+$ ]]
당신이 원할 수도 있는 테스트입니다.행간을 허용하려면 -
다음과 같이 수정하십시오 [[ "$1" =~ ^-?[0-9]+$ ]]
. 전체 테스트 조각은 다음과 같을 수 있습니다.
[ "$#" -eq 2 ] && `[[ "$1" =~ ^-?[0-9]+$ ]]` && `[[ "$2" =~ ^-?[0-9]+$ ]]`
내부 [[ ]]
변수/매개변수는 큰따옴표로 묶을 수 없으며 확장된 값은 단어 분할 및 글로빙을 거치지 않습니다. 그래야 쓸 수 있고 [[ $1 =~ ^-?[0-9]+$ ]]
안전해요. 예외입니다. 일반적으로 변수는 큰따옴표로 묶어야 합니다. 여기서 큰따옴표는 아무런 방해가 되지 않으므로 이 좋은 일반적인 관행에 익숙해지려면 어쨌든 인용하는 것이 좋습니다.
를 사용하여 문제를 해결했다고 주장합니다 [[ "$@" -eq ^[0-9] ]]
. 미안해요, 난 당신을 믿지 않아요. 정확히 두 개의 위치 매개변수가 있고 숫자인 경우 원하는 것을 테스트하는 것은 말할 것도 없고 이것이 구문적으로 정확할 수 있는 방법도 없습니다. 다른 경우에는… 아직 방법이 보이지 않습니다.
... 사용 [[ "$@" =~ ^[0-9] ]]
(귀하의 의견에서 질문과 일치하지 않음). 이는 적절한 해결책이 아닙니다. 내 테스트에 따르면 "$@"
내부는 단어 분할 및 글로빙 없이 [[ ]]
따옴표가 없는 한 단어로 처리되는 것처럼 동작합니다 . $@
이는 일반 변수가 내부에서 작동하는 방식과 매우 유사합니다 [[ ]]
. 비록 사전에 명확하지는 않았지만 "$@"
일반 변수와 같지 않기 때문입니다.
참고 사항: 이런 이유로 나는 "$@"
inside 를 사용하고 싶지 않았습니다 [[ ]]
. 나는 그것이 옳은 일인 시나리오를 상상할 수 없습니다.
정확히 두 개의 위치 매개변수가 있는 경우 "솔루션"은 가 됩니다 [[ "$1 $2" =~ ^[0-9] ]]
. 이는 구문적으로 유효하며 스크립트에 대한 첫 번째 인수의 첫 번째 문자가 숫자인지 확인합니다. 만이. Run 을 실행 ./scriptgoeshere.sh 0h well
하면 인수가 테스트를 통과합니다.
노트:
[0-9]
(globbing 패턴 또는 정규식)은 현재 로케일에 따라 다릅니다. 예상대로 작동할 가능성이 높지만 기술적으로는 선행9
또는0
이후2
에 로케일을 갖는 것이 가능합니다0-9
. 숫자와 일치하는 가장 일반적인 방법은 입니다[[:digit:]]
. 보다이것.반면에
$1
및/또는$2
쉘 연산($((…))
)[ "$1" -ge 50 ]
등을 사용할 수도 있습니다. 그렇다면 아라비아 숫자만 있으면 됩니다. 귀하의 로케일에 포함 하더라도[[:digit:]]
(아마도 그렇습니다), 다른 숫자도 포함될 수 있습니다. 고려하다[0123456789]
; 이는 명시적이며 로케일에 종속되지 않습니다.일치하는 모든 문자열 이 및/또는
^-?[0-9]+$
관점에서 정수로 간주되는 것은 아닙니다 (예: 수행할 때 ). 각 도구에는 처리할 수 있는 정수 범위가 있습니다. 마찬가지로 쉘 연산에 범위를 벗어난 정수를 설명하는 숫자 문자열을 입력하면 수학적으로 잘못된 결과가 나올 수 있습니다.[
[[
[ "$1" -eq 0 ]
수학적으로
1.00
는 정수입니다. 일부 도구에서는 이를 정수로 받아들일 수도 있고 일부 도구에서는 그렇지 않을 수도 있습니다. 는 어때1e100
?