알파벳 루프


12

이것은 OSX에서 완벽하게 작동합니다

#!/bin/bash
chars=( {a..z} )
n=3
for ((i=0; i<n; i++))
do
  echo "${chars[i]}"
done

그러나 우분투에서 실행할 때 다음 오류가 발생합니다.

ForLoopAlphabetTest.sh: 2: ForLoopAlphabetTest.sh: Syntax error: "(" unexpected

문제를 해결할 수없는 것 같습니다. 어떤 제안?


2
이것은 우분투에서 작동합니다.
Pilot6

16.04 bash 4.3에서 스크립트로 작동하도록 할 수 없습니다. 그러나 그것을 터미널에 복사하면 작동합니다.
denski

답변:


25

아마도 다음과 같이 스크립트를 실행하고있을 것입니다.

sh ForLoopAlphabetTest.sh

우분투으로 sh하는 심볼릭 링크된다 dash; 같은 dash배열의 개념이 없습니다, 당신은 구문 오류를 얻고있다 (.

이 스크립트는에서 완벽하게 작동 bash하므로 bash인수 로 실행하면 괜찮습니다 .

bash ForLoopAlphabetTest.sh

이제 bash스크립트에 shebang이 있으므로 스크립트를 실행 파일 ( chmod u+x ForLoopAlphabetTest.sh)로 만들고 다음과 같이 실행할 수 있습니다.

/path/to/ForLoopAlphabetTest.sh

또는 스크립트 디렉토리에서 :

./ForLoopAlphabetTest.sh

또한 스크립트에는 중괄호 확장 {a..z}과 C 스타일 for구문이 for (( ... ))포함되어 있습니다 dash. 따라서 목표가 이식성이라면 POSIX sh구문 만 살펴 봐야 합니다.


감사합니다. 대시의 배열 개념 부족을 우회하는 방법이 있습니까?
denski

3
@denski /bin/sh유닉스 계열 운영 체제에서 실행할 수있는 이식 가능한 스크립트를 작성 하려면 배열을 사용할 수 없습니다. Bash (및 다른 쉘)는 매우 편리하고 항상 더 이식 가능한 코드로 쉽게 대체 할 수 없기 때문에 추가했습니다. 그러나 스크립트의 경우 특히 bash 특정 기능을 사용하지 않고도 문제없이 수행 할 수 있습니다. 그렇게하는 방법에 관심이 있습니까?
Eliah Kagan

도움이 될만한 독서를 제안했다면. 감사.
denski

1
@denski 나는 몇 가지 링크와 예제가 포함 된 답변게시했습니다 . 이전의 주석에서, 루프와 배열에 C 스타일을 사용했지만 괄호 확장에 대해서는 언급하지 않았습니다. 내 대답은 세 가지없이 모두 수행하는 방법을 다룹니다. 참고 대답 (하지 광산 즉, heemayl이의) 문제에 대한 기본 솔루션입니다; 광산은 bash 특정 기능에 의존 할 수없는 경우 스크립트를 다시 작성하는 방법에 중점을 둡니다.
Eliah Kagan

@heemayl 기록을 위해, 나는 당신이 내가 스크립트를 실행하고 있다는 가정에서 정확하다고 덧붙이고 싶었다sh
denski

10

스크립트는 모든 Bourne 스타일 쉘에서 제공하지 않는 Bash 쉘의 세 가지 기능을 사용합니다. 으로 heemayl는 말한다 , 당신은 단순히 함께 해당 스크립트를 실행할 수 있습니다 bash대신 sh. 귀하의 hashbang의 상단 (시 라인 #!/bin/bash)을 지정 bash당신이 경우 만 효과가 실행 으로 스크립트를 heemayl 설명 . 당신이 스크립트의 이름을 전달하면 sh, sh자동으로 호출하지 않습니다 bash, 단순히 스크립트를 실행합니다. 때문입니다 스크립트가 실제로 실행되면, hashbang 라인은 효과가 없습니다 .

다른 대안 은 Bash 기능에 의존하지 않는 완전히 이식 가능한 스크립트 를 작성 해야하는 경우 스크립트없이 변경되도록 스크립트를 변경하는 것입니다. 사용하는 Bash 기능은 다음과 같습니다.

  • 어레이 . 이것이 처음이므로 Dash shell로 스크립트를 실행하려고 할 때 오류가 발생했습니다 . 에 ( {a..z} )할당 된 괄호로 묶은 expression chars은 배열을 만들고 ${chars[i]}루프에 표시 되는 배열을 만듭니다 .
  • 중괄호 확장. Bash 및 기타 여러 셸에서 {a..z}로 확장되었습니다 a b c d e f g h i j k l m n o p q r s t u v w x y z. 그러나 이것은 Bourne 스타일 쉘의 보편적 인 (또는 표준화 된) 기능이 아니며 Dash는이를 지원하지 않습니다.
  • 는 C 스타일의 대체 for-loop 구문 . 비록 Bash에만 국한되지않는 산술 확장 에 기초 하지만 (일부는 POSIX 호환이 아닌 오래된 쉘 도 없지만) C 스타일 루프 Bash-ism이며 널리 이식되지 않습니다. 다른 껍질.for

Bash는 특히 Ubuntu와 같은 GNU / Linux 시스템에서 광범위하게 사용할 수 있으며 macOS 및 기타 여러 시스템에서도 사용할 수 있습니다. Bash 전용 기능을 얼마나 많이 사용하고 있는지를 고려할 때 스크립트를 실행할 때 Bash (또는 사용중인 기능을 지원하는 다른 쉘)를 사용하고 싶을 수도 있습니다.

그러나 원하는 경우 이식 가능한 구성으로 바꿀 수 있습니다. 배열과 C 스타일 for루프는 쉽게 교체 할 수 있습니다. 중괄호 확장없이 (및 스크립트에서 하드 코딩하지 않고) 문자 범위를 생성하는 것은 약간 까다로운 부분입니다.


먼저 소문자 라틴 문자를 모두 인쇄하는 스크립트가 있습니다.

#!/bin/sh

for i in $(seq 97 122); do
    printf "\\$(printf %o $i)\n"
done
  • seq명령은 숫자 시퀀스를 생성합니다. 명령 대체를$( ) 수행 하므로 의 출력으로 대체됩니다 . 이것들은 through 의 문자 코드 입니다 .$(seq 97 122)seq 97 122az
  • 강력한 printf명령 문자 (예를 들어, 문자 코드로 바꿀 수 printf '\141'인쇄 aa로 이어 개행 )하지만, 코드가 있어야 8 진수 동안 seq만 출력 진수 . 따라서 printf두 번 사용 했습니다. inner printf %o $i는 십진수 (로 제공 seq)를 8 진수 로 변환하고 외부 명령 으로 대체 합니다 printf. ( 16 진수 를 사용할 수도 있지만 더 간단하지 않고 이식성이 떨어 집니다.)
  • printf\그 뒤에 8 진수가 해당 코드의 문자 및 \n개행 문자로 해석 됩니다 . 그러나 은 또한 \이스케이프 문자로 사용 합니다. \앞에 $방지 할 수 $에서 발생하는 확장의 원인 (이 경우, 명령 치환 )을하지만 난 그것을 방지하기 위해 싶지 않아, 내가 서로를 탈출 있도록 \; 그것이 이유입니다 \\. 은 초 \전에 n달리하기 때문에 탈출 할 필요가 없습니다 \$, \n이중 인용 문자열에 쉘에 특별한 의미를 가지고 있지 않습니다.
  • 쉘 프로그래밍에서 큰 따옴표와 백 슬래시가 사용되는 방법에 대한 자세한 내용 은 국제 표준의 인용 섹션을 참조하십시오 . 참조 3.1.2 인용배쉬 레퍼런스 매뉴얼 특히, 3.1.2.1 탈출 문자3.1.2.3 큰 따옴표 . (여기 에 전체 섹션이 있습니다.) 작은 따옴표 ( ')도 쉘 인용 구문의 중요한 부분입니다.이 스크립트에서는 따옴표를 사용하지 않았습니다.

이것은 대부분의 유닉스 계열 시스템에 이식 가능하며 사용하는 Bourne 스타일 쉘에 의존하지 않습니다. 그러나 유닉스 계열 시스템은 seq기본적으로 설치되어 있지 않습니다 ( jot대부분의 GNU / Linux 시스템에서는 기본적으로 설치되지 않는 대신 사용 하는 경향이 있습니다 ). 다음과 같은 경우 루프를 사용 expr하거나 산술 대체를 사용하여 이식성을 더욱 높일 수 있습니다.

#!/bin/sh

i=97
while [ $i -le 122 ]; do
    printf "\\$(printf %o $i)\n"
    i=$((i + 1))
done

즉, 사용 while과 -loop을 명령 경우에만 루프 계속 범위이다.[$i


스크립트는 전체 알파벳을 인쇄하는 대신 변수를 정의 n하고 첫 번째 $n소문자를 인쇄합니다 . Bash 전용 기능에 의존하지 않고 Dash에서 작동하지만 다음과 같은 스크립트 버전이 있습니다 seq.

#!/bin/sh

n=3 start=97
for i in $(seq $start $((start + n - 1))); do
    printf "\\$(printf %o $i)\n"
done

n스크립트에서와 같이 인쇄되는 문자 수 를 변경 하여 값을 조정합니다 .

필요하지 않은 버전은 다음과 같습니다 seq.

#!/bin/sh

n=3 i=97 stop=$((i + n))
while [ $i -lt $stop ]; do
    printf "\\$(printf %o $i)\n"
    i=$((i + 1))
done

, 거기에 $stop하나 제가 사용하므로, 즉 인쇄되어야한다 마지막 문자의 문자 코드보다 -lt가 아닌 (보다 작음) -le(이하)을 가진 [명령. (또한 만들고 stop=$((i + n - 1))사용 하기 위해 노력했을 것입니다 [ $i -le $stop ]).


1
이것은 교육에 대한 것보다 엄청나게 자세한 답변입니다. 저는 초보자입니다. 스크립트를 작성하는 방식은 작동 할 때까지 인터넷에서 찾은 작업 요소를 하나로 모으는 것입니다. 필자가 스크립트로 작성하는 작업을 수행하는 1) 더 좋고 2) 더 간단한 방법이 있다는 것은 의심의 여지가 없습니다.
denski

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.