getopts 이후 스크립트 매개변수 구문 분석

getopts 이후 스크립트 매개변수 구문 분석

다음을 사용하여 스위치를 구현하는 스크립트가 있습니다.선택 항목 가져오기. 그러나 다음 매개변수를 참조할 수 없습니다.

내 스크립트는 로컬 개발 환경에서 웹 사이트의 백업을 백포트하는 데 사용됩니다. -p일부 배포 후 단계를 실행하기 위한 스위치를 추가했습니다 . 이것은 내 구문입니다.

backport -p /path/to/website_backup.sql.gz

그래서 전환하기 전에 파일이 지정되었는지, 파일이 올바른지 테스트하고 있습니다. 파일명 경로가 유일한 매개변수이므로 꼭 필요하다고 가정할 수 있으며 첫 번째 매개변수( $1)가 될 것입니다.

if [[ $# -eq 0 ]] ; then
  echo 'Specifcy the sql file to backport.';
  exit 0;
fi

if [[ ! -f "$1" ]]; then
  echo "$1 is not a valid file.";
  exit 0;
fi

내가 찾은이 답변getopts를 사용하여 스위치 매개변수를 구문 분석하는 방법의 예를 보여줍니다.

while getopts "p" opt; do
  case $opt in
    p) p_post_deploy=true ;; # Handle -a
  esac
done

물론, $1getopts를 구현한 후에는 as 매개변수를 사용하면 작동하지 않습니다. 스위치가 없어도 괜찮습니다. 그러나 첫 번째 매개변수인 스위치를 추가하면 스크립트가 파일인지 테스트합니다.

$ backport -p /path/to/website_backup.sql.gz
-p is not a valid file.

따라서 스위치가 도입되면서 명령의 특정 위치에 나타나는 매개변수에 의존할 수 없게 되었습니다. $2스위치가 없으면 파일 이름 인수가 두 번째 인수가 될 수 없기 때문에 하드 코딩이 작동하지 않습니다. 저는 스위치 후에 매개변수를 허용하고, 새 스위치 자체를 처리하기 위해 코드만 업데이트하면서 나중에 새 스위치를 도입할 수 있게 해주는 솔루션을 원합니다. 나중에 이동할 수 있음) 새로운 스위치 도입).

getopts를 사용하여 스위치를 구문 분석하는 방법을 알려주는 unix.stackexchange 질문에 대한 답변을 살펴보았습니다.답변 중 하나$*나머지 매개변수를 나타내는 변수로 언급됩니다.

if [[ "$*" -eq 0 ]] ; then
  echo 'Specifcy the sql file to backport.';
  exit 0;
fi

그런데 사용하려고 하면 구문을 정확하게 표현하지 못하고 파싱 오류가 발생합니다.

~/scripts/backport: line 14: [[: /d/Downloads/database.sql.gz: syntax error: operand expected (error token is "/d/Downloads/database.sql.gz")

getops 후에 파일 이름 매개변수를 테스트하는 방법은 무엇입니까?


현재 스크립트 버전은 다음과 같습니다.

$ cat backport
#!/bin/bash

set -e

while getopts "p" opt; do
  case $opt in
    p) p_post_deploy=true ;;
  esac
done

shift $(($OPTIND - 1))
# testing what this variable looks like
printf "Remaining arguments are: %s\n" "$*"

if [[ "$*" -eq 0 ]] ; then
  echo 'Specifcy the sql file to backport.';
  exit 0;
fi

if [[ ! -f "$*" ]]; then
  echo "$* is not a valid file.";
  exit 0;
fi

drush @local.dev sql-drop -y ;
zcat $1 | drush @local.dev sqlc ;
drush @local.dev cr;

if [ ! -z "$p_post_deploy" ] ; then
  echo "Running post-deploy..."
  SCRIPT_PATH=$(dirname "$BASH_SOURCE")
  source "$SCRIPT_PATH/post-deploy"
  post_deploy
fi

답변1

의사소통이 원활하지 못해서 제 탓만 할 수 밖에 없는데, 쿠살라난다가 제가 찾던 답을 댓글로 주셨네요.

getopts파싱 ​​스위치를 사용한 후

while getopts "p" opt; do
  case $opt in
    p) p_post_deploy=true ;;
  esac
done

이 줄

shift "$((OPTIND - 1))"

모든 스위치는 매개변수 목록에서 제거되므로 스위치가 없는 것처럼 위치 매개변수를 다시 사용할 수 있습니다.

쉘은 OPTIND자동으로 재설정되지 않습니다. 수동으로 재설정해야 합니다.

답변2

테스트 구조의 적용

if [[ "$*" -eq 0 ]]

부정확하다. -eq에 사용됩니다정수그리고 $*인수 목록이 해당 숫자가 아닌 나머지 모든 인수를 참조한다는 점을 감안할 때, 나머지 인수 목록에 단 하나의 요소만 포함되지 않는 한 테스트 구성은 구문 오류를 생성할 수밖에 없습니다. 정수를 나타냅니다(이것은 달성하려는 것이 아닙니다).

이제 실제 작업에서는 "비옵션 매개변수"(예:아니요-<some letter>임의의 순서를 허용하는 한(즉, 파일 이름이 마지막에 와야 한다고 지정하지 않는 한) 옵션 인수와 함께 "알림"이 앞에 옵니다. 를 사용하려면 getopts파일 이름을 옵션 인수로 지정하기를 원할 수도 있습니다 -f <filename>. 그런 다음 사용할 수 있습니다

while getopts "pf:" opt; do
  case $opt in
    p)
       p_post_deploy=true
    ;;
    f)
       backportfile=$OPTARG
    ;;
  esac
done

getopts파일 이름이 지정되지 않으면 자동으로 오류가 발생합니다.

./test.sh: option requires an argument -- f

그런 다음 나중에 다음과 같이 파일이 존재하는지 테스트할 수 있습니다.

if [[ ! -f "$backportfile" ]]
then
  echo "$backportfile is not a valid file"
  exit 1
fi

관련 정보