스크립트 셸 - 두 가지 조건이 충족되면 에코를 출력하는 방법은 무엇입니까? (숫자만, 조건 2개와 일치함)

스크립트 셸 - 두 가지 조건이 충족되면 에코를 출력하는 방법은 무엇입니까? (숫자만, 조건 2개와 일치함)

저는 쉘 스크립팅을 처음 접했고 기본 사항을 배우려고 노력하고 있습니다. "./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 && barbar성공 하면 실행됩니다 foo. 두 번째는 으로 확장된 [[경우에만 테스트되었으므로 정확히 한 자리이기 때문에 성공해야 했습니다 . 이 경우 두 번째는 아무것도 변경하지 않습니다.$#22[[


실수를 깨닫고 $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?

관련 정보