2014-09-24 5 views
1

내 스크립트가 주 작업을 진행하기 전에 내 스크립트가 의존하는 모든 비 POSIX 명령이 있는지 확인하려고합니다. 이렇게하면 나중에 스크립트가 누락 된 명령으로 인해 오류를 생성하지 않도록 할 수 있습니다.POSIX 셸에서 큰 따옴표로 묶은 문자열을 반복하는 방법은 무엇입니까?

모든 비 POSIX 명령의 목록을 DEPS이라는 변수에 보관하여 스크립트가 발전하고 더 많은 명령에 의존하므로이 변수를 편집 할 수 있습니다.

스크립트가 공백이있는 명령을 지원하도록하고 싶습니다. my program.

이것은 내 스크립트입니다. "myprogram" 아래의 출력에서 ​​볼 수 : "my program"이 두 for 루프를 반복하면서 단어로 분리되어 있기 때문에

#!/bin/sh 
DEPS='ssh scp "my program" sftp' 

for i in $DEPS 
do 
    echo "Checking $i ..." 
    if ! command -v "$i" 
    then 
     echo "Error: $i not found" 
    else 
     echo "Success: $i found" 
    fi 
    echo 
done 

그러나이 작동하지 않습니다.

# sh foo.sh 
Checking ssh ... 
/usr/bin/ssh 
Success: ssh found 

Checking scp ... 
/usr/bin/scp 
Success: scp found 

Checking "my ... 
Error: "my not found 

Checking program" ... 
Error: program" not found 

Checking sftp ... 
/usr/bin/sftp 
Success: sftp found 

내가 기대 출력은 다음과 같습니다 준수 스크립트 POSIX를 유지하면서

# sh foo.sh 
Checking ssh ... 
/usr/bin/ssh 
Success: ssh found 

Checking scp ... 
/usr/bin/scp 
Success: scp found 

Checking my program ... 
Error: my program not found 

Checking sftp ... 
/usr/bin/sftp 
Success: sftp found 

가 어떻게이 문제를 해결할 수 있습니까?

+1

POSIX 쉘에서이 작업 BashFAQ 번호 50 주어진 모든 해답이에 지점이 질문에 대한 직접적이며, 일부 (명시 적으로 호출 아웃) POSIX 호환 예를 _does_ 동안 : HTTP : //이 mywiki .wooledge.org/BashFAQ/050 –

+0

BTW, 이식성이 작업 1 일 경우'autoconf '를 사용하는 것이 좋지 않습니다. autoconf는 POSIX sh가 아닌 POSIX Bourne을 실행하는 플랫폼에서도 작동하도록 테스트됩니다. –

답변

1

매개 변수 확장 후 단계가 문자열 분할 및 glob 확장 (이 아니고 구문 수준 구문 분석 (예 : 따옴표 처리)이기 때문에 발생합니다. 구문 분석 프로세스의 시작 부분으로 다시 이동하려면 eval을 사용해야합니다. 솔직히


, 가장 좋은 방법은하려면 다음 중 하나를

  1. 대상이 아니라
  2. 하지 마십시오 POSIX를 지원하는 것보다 배열 (KSH, 배쉬, zsh을, 등)를 지원하는 쉘 변수에서 값을 검색합니다.

... 올바른 배열 지원은 현대 쉘에서 유비쿼터스입니다. 분명히 신뢰할 수없는 데이터를 처리 할 때 분명하지 않은 코드를 작성하는 경우이를 사용하지 않으면 훨씬 더 어렵습니다. 당신은

deps='goodbye "cruel world"' 
eval "set -- $deps" 
for program; do 
    echo "processing $program" 
done 

당신이 함수의 내부를 할 경우


eval를 사용하여, 당신은 설정 위험이라도 할 수있는 내용을 저장하기 위해 [email protected]를 사용하는 옵션을 가지고 말했다 전역 목록을 변경하지 않고 함수의 인수 목록 만 덮어 씁니다.

대체로 eval "yourfunction $deps"은 함수 내에서 인수 목록을 $deps의 내용에 대한 일반적인 구문 분석 및 확장 단계를 모두 실행 한 결과로 설정하여 동일한 효과를 나타냅니다.

1

스크립트가 제어 할 수 있으므로 eval을 합리적인 안전성과 함께 사용할 수 있으므로 @Charles Duffy의 대답은 간단하고 좋은 해결책입니다. 그걸 써.:)

또한 configure 스크립트를 생성하는 데 autoconf을 사용하는 것이 좋습니다. 명령과 확인 적어도 ... 어떤 방법 일반적인 문제를 solvle하는 아이디어 스크립트를 구성 확인 ... 훨씬 더

당신이 당신의 자신의 구현을 재생하려면

: 두 그룹으로

  • 나눈다 dependecies을
    • core_deps - 유닉스 도구, 일반적으로 sed처럼, 스크립트 자체에 필요한 것, catcp 등. 이러한 프로그램은 이름이나 $ PATH에 공백을 포함하지 않습니다.
    • runtime_deps - 응용 프로그램에는 필요한 프로그램이 있지만 스크립트 자체에는 필요하지 않은 프로그램입니다. 그래서 당신은 사용할 수 있습니다 - (당신은 예를 들어, 라이브러리를 확인해야하는 경우, 예를 들어, 또는 그 이상)
  • 당신이 함수 인수로 그들을 점점하지 않는
  • 은 공간을 구분 요소를 for 루프를 사용하지 않을 두 단계의 점검을 스크립트를 시작하면 다음과 같이 될 수 "[email protected]"

으로 :

_check_core_deps() { 
    for _cmd 
    do 
     _cpath=$(command -v "$_cmd") 
     case "$_cpath" in 
     /*) continue;; 
     *) echo "Missing install dependency [$_cmd] - can't continue" ; exit 1 ;; 
     esac 
    done 
    return 0 
} 

core_deps="grep sed hooloovoo cp" #list of "core" commands - they doesn't contains spaces 
_check_core_deps $core_deps || exit 1 

위의 존재에 날려 버리겠다 "hooloov oo "명령. :)

이제 안전하게 계속 진행할 수 있습니다. 설치 스크립트에 필요한 모든 핵심 명령을 사용할 수 있습니다. 다음 단계에서는 다른 이상한 종속성을 확인할 수 있습니다.

몇 가지 아이디어 :

# function what returns your dependecies as lines from HEREDOC 
# (e.g. could contain any character except "\n") 
# you can decorate the dependecies with comments... 
# because we have sed (checked in the 1st step, can use it) 
# if want, you can add "fields" too, for some extended functinality with an specified delimiter 
list_deps() { 
    _sptab=$(printf " \t") # the $' \t' is approved by POSIX for the next version only 
    #the "sed" removes comments and empty lines 
    #the UUOC (useless use of cat) is intentional here 
    #for example if you want add "tr" before the "sed" 
    #of course, you can remove it... 
    cat - <<DEPS |sed "s/[$_sptab]*#.*//;/^[$_sptab]*$/d" 
########## DEPENDECIES ############ 
#some comment 
ssh 
scp 
sftp 
     #comment 
#bla bla 
my program #some comment 
/Applications/Some Long And Spaced OSX Apllication.app 
DEPS 
########## END of DEPENDECIES ##### 
} 

_check_deps() { 
#in the "while" loop you can use IFS=: or such and adding anouter variable to read 
#for getting more fields for some extended functionality 
list_deps | while read -r line 
do 
    #do any checks with the line 
    #implement additional functionalities as functions 
    #etc... 
    #remember - your in an subshell here 
    printf "command:%s\n" "$line" 
done 
} 

_check_deps 

한 가지 더 :) (또는 2) 당신이 어떤 변수의 내용에 대해 의심하는 경우

  • echo를 사용하지 마십시오. POSIX는 이스케이프 된 문자 (예 : echo "some\nwed")가있을 때 어떻게 작동해야하는지 정의하지 않습니다. 사용 :
printf '%s' "$variable" 
  • 이 ... ... 그들은 환경 변수 만있어 "DEPS"와 같은 대문자 변수 만 사용하지 않을
2

나는 응답 I를 반복합니다 이전 질문에 : for 루프보다는 here 문서로 while 루프를 사용하십시오. 문자열에 개행 문자를 포함 할 수 있습니다. 명령 이름에 공백이 포함될 수있는 경우 문자열에서 명령 이름을 분리하는 데 필요한 모든 것입니다. (명령 이름은 줄 바꿈을 포함 할 경우 강력하게 그 이름을 바꾸는 것이 좋습니다.) 최대 POSIX의 호환성을 위해

, printf를 사용 echo의 POSIX 사양으로 인해 echo이 정의에 앞서 다양한 쉘에 구현 된 방법의 차이에 현저하게 느슨한 때문에 표준의

deps="ssh 
scp 
my program 
sftp 
" 
while read -r cmd; do 
    printf "Checking $cmd ...\n" 
    if ! command -v "$cmd"; then 
     printf "Error: $i not found\n" 
    else 
     printf "Success: $cmd found\n" 
    fi 
    printf "\n" 
done <<EOF 
$deps 
EOF 
+0

니스. 이것은 제가 준 것보다 훨씬 더 나은 대답입니다. –

관련 문제