2011-01-03 3 views
18

저는 이미 getopts에 대해 알고 있습니다. 그러나 이것은 괜찮습니다. 그러나 필수 인수에 대해서조차도 플래그를 가져야 만한다는 것은 짜증나게합니다.인수를 취하는 bash 스크립트를 작성하는 방법은 무엇입니까?

이상적으로,이 형태의 인수를받는 스크립트를 가질 수 싶습니다 스크립트는 출력을 가지고 있다고 말합니다 예를

script.sh -rvx output_file.txt 

에 대한

script.sh [optional arguments] [anything required] 

파일. 이 작업을 수행하는 쉬운 방법이 있습니까?

내가 아는 한 getopts를 사용하면 다음과 같이 보일 것입니다 : script.sh -rvx -f output_file.txt, 그리고 그다지 깨끗하지는 않습니다.

필요한 경우 파이썬을 사용할 수도 있지만 2.4 버전 만 사용할 수 있습니다. 이는 약간 날짜가 맞습니다.

답변

29

내장 된 getopts를 사용하지 말고 대신 getopt (1)을 사용하십시오. 그들은 (미묘하게) 다르며 다른 것들을 잘합니다. 당신 시나리오 당신이 할 수 있습니다 :

#!/bin/bash 

eval set -- $(getopt -n $0 -o "-rvxl:" -- "[email protected]") 

declare r v x l 
declare -a files 
while [ $# -gt 0 ] ; do 
     case "$1" in 
       -r) r=1 ; shift ;; 
       -v) v=1 ; shift ;; 
       -x) x=1 ; shift ;; 
       -l) shift ; l="$1" ; shift ;; 
       --) shift ;; 
       -*) echo "bad option '$1'" ; exit 1 ;; 
       *) files=("${files[@]}" "$1") ; shift ;; 
     esac 
done 

if [ ${#files} -eq 0 ] ; then 
     echo output file required 
     exit 1 
fi 

[ ! -z "$r" ] && echo "r on" 
[ ! -z "$v" ] && echo "v on" 
[ ! -z "$x" ] && echo "x on" 

[ ! -z "$l" ] && echo "l == $l" 

echo "output file(s): ${files[@]}" 

편집 : 완성도 나는 인수를 필요로하는 옵션 처리의 예를 제공하고 있습니다.

+0

정확히 내가 원하는 것처럼 보입니다. 그러나 이것에 대한 하나의 질문 : 인수 (예 : -l file.txt)를 취하는 플래그를 허용하려면 구문은 무엇입니까? 다시 한번 감사드립니다. –

+0

getopt man 페이지를 참고하십시오. 간단히 : 옵션에 콜론을 추가하십시오 (예 :' "-rv : x"', 인수가 필요한 v). 긴 옵션이 지원되기 때문에 내장 된 getopt보다 우선합니다. 추가 비 선택적 인수를 직접 처리해야합니다. – Sorpigal

+0

정말 고마워요. 훌륭한 반응. –

11

getops를 사용하는 경우 case 문 다음에 $OPTIND-1으로 이동하십시오. 그렇다면 $*에 남아있는 것은 다른 모든 것일 것입니다. 이는 아마도 당신이 원하는 것입니다.

shift $((${OPTIND} - 1)); echo "${*}" 
+0

예. $ #를 검사하여 필요한 인수가 제대로 전달되었는지 확인한 다음 평소와 같이 $ 1, $ 2 등으로 액세스하십시오. –

4

당신은 환상에서 고통 받고 있습니다. getopts을 사용하면 필수 인수에 플래그 글자를 접두사로 사용할 필요가 없습니다. 나는 나의 대본에서 적절한 예를 찾으려고 노력했다. 이것은 반 (半) 근사입니다. rcsunco이라고하며 RCS에서 체크 아웃을 취소하는 데 사용됩니다. 나는 그것을 잠시 동안 수정하지 않았다. 나는 RCS에서 완전히 마이그레이션하지 않았기 때문에이를 자주 사용합니다.

#!/bin/sh 
# 
# "@(#)$Id: rcsunco.sh,v 2.1 2002/08/03 07:41:00 jleffler Exp $" 
# 
# Cancel RCS checkout 

# -V print version number 
# -n do not remove or rename checked out file (like SCCS unget) (default) 
# -r remove checked out file (default) 
# -k keep checked out file as $file.keep 
# -g checkout (unlocked) file after clean-up 
# -q quiet checkout 

: ${RCS:=rcs} 
: ${CO:=co} 

remove=yes 
keep=no 
get=no 
quiet= 

while getopts gknqrV opt 
do 
    case $opt in 
    V) echo "`basename $0 .sh`: RCSUNCO Version $Revision: 2.1 $ ($Date: 2002/08/03 07:41:00 $)" | 
     rcsmunger 
     exit 0;; 
    g) get=yes;; 
    k) keep=yes;; 
    n) remove=no;; 
    q) quiet=-q;; 
    r) remove=yes;; 
    *) echo "Usage: `basename $0 .sh` [-{n|g}][-{r|k}] file [...]" 1>&2 
     exit 1;; 
    esac 
done 

shift $(($OPTIND-1)) 

for file in $* 
do 
    rfile=$(rfile $file) 
    xfile=$(xfile $rfile) 
    if $RCS -u $rfile 
    then 
     if [ $keep = yes ] 
     then 
      if [ -f $xfile ] 
      then 
       mv $xfile $xfile.keep 
       echo "$xfile saved in $xfile.keep" 
      fi 
     elif [ $remove = yes ] 
     then rm -f $xfile 
     fi 
     if [ $get = yes ] && [ $remove = yes -o $keep = yes ] 
     then $CO $quiet $rfile 
     fi 
    fi 
done 

반 준칙입니다. 선택적 인수 뒤에 파일 이름을 제공하지 않으면 스크립트는 아무 것도하지 않습니다. 그러나 필요하다면 'shift'다음에 필수 인수가 있는지 확인할 수 있습니다. 나의 또 다른 대본에는 필수적인 주장이 있습니다.

... 
shift $(($OPTIND - 1)) 

case $# in 
2) case $1 in 
    install) MODE=Installation;; 
    uninstall) MODE=Uninstallation;; 
    *)   usage;; 
    esac;; 
*) usage;; 
esac 

그래서, 명령 (jlss)이 같은 -d $HOME 같은 선택적 인수를 취할 수 있지만, install 또는 uninstall 중 하나가 설치 뭔가의 이름 다음에 필요 :이 포함되어 있습니다.

jlss install program 

그러나 선택 모드는 다음과 같습니다 : 사용의 기본 모드입니다이 약 12 ​​옵션을 가지고 있기 때문에

jlss -d $HOME -u me -g mine -x -p install program 

내가 jlss을 모두 보여주지 않았다 - 그렇지 rcsunco만큼 컴팩트 .당신은 옵션 인수 전에 필수 인수를 처리 한 경우


, 당신은 좀 더 많은 일을해야 할 것 :

  • 당신은 필수 인수를 데리러하려는 그들을 밖으로 이동 방법.
  • 그런 다음 선택적 인수를 플래그로 처리합니다.
  • 마지막으로, 적절한 경우 추가 '파일 이름'인수를 처리합니다.

옵션 인수가 삽입 된 필수 인수 (필수 인수 전후 모두)를 다루는 경우, 더 많은 작업이 필요합니다. 이것은 많은 VCS 시스템에서 사용됩니다. CVS와 GIT 모두 시설이 : 여기

git -global option command [-sub option] [...] 

, 당신은 전역 옵션을 얻기 위해 하나 개 getopts 루프를 실행합니다; 의무적 인 논점을 찾아라. 두 번째 getopts 루프를 실행하여 하위 옵션을 가져오고 ('파일 이름'인수를 통해 최종 루프를 실행할 수도 있습니다).

인생이 재미 있지 않습니까?

2

을 그리고 난 당신이 getopt를 사용하지 않도록, 완전히 반대의 일을 듣고, 그러나 getopts 내장.

Cross-platform getopt for a shell script

getopt를 사용하지 마십시오 (1). getopt는 빈 인수 문자열을 처리 할 수 ​​없으며 공백이 포함 된 인수는 입니다. 이 존재한다는 사실을 잊어 버리십시오.

POSIX 셸 (및 기타)은 을 대신 사용하는 getopts를 제공합니다.

관련 문제