사용자가 매개변수를 추가하는 대신 매개변수 앞에 추가하는 스크립트가 있습니다. 즉 command C
, command B C
, , command A B C
등을 호출할 수 있습니다.
에서 할 수 있는 것처럼 이러한 매개변수를 오른쪽에서 간단히 이동할 수 있기를 바랍니다 shift
.
나는 shift-right
다음과 같이 동작하는 명령을 상상하고 있습니다.
echo "$@" # A B C
shift-right
echo "$@" # A B
shift-right
echo "$@" # A
shift-right
echo "$@" #
echo "$#" # 0
이것을 달성하는 깨끗한 방법이 있습니까? 이 문제를 해결할 수 있다는 것을 알고 있지만 shift
유사한 솔루션이 더 좋고 간단할 것입니다.
XY 질문 의견에 대한 응답으로 나의 구체적인 사용 사례는 포트 또는 호스트와 포트를 사용하는 명령입니다(예: command 123
또는 ) command remotehost 123
. 나는 사용자가 이를 역순으로(포트 다음 호스트) 지정하도록 하고 싶지 않습니다.
다음과 같이 말하는 것은 매우 깨끗할 것입니다(분명히 테스트되지 않음).
port=${@: -1}
shift-right
host=${1:-localhost}
하지만 실제로는 이 특정 예를 해결하는 더 좋은 방법이 있더라도 이 문제에 대해 궁금합니다.
shift-right
참고용으로 두 개의 인수가 없는 경우를 처리하는 매우 깔끔한 방법은 다음과 같습니다 .
port=${@: -1}
host=${2:+$1}
host=${host:-localhost}
그러나 매개변수 수가 증가함에 따라 이것이 얼마나 다루기 어려워지는지 이해할 수 있기를 바랍니다.
답변1
위치 인수 목록이 다음과 같은 경우:
$ set -- 0wer 1wdfg 2erty 333 4ffff 5s5s5
그러면 마지막 인수 없이 인수가 인쇄됩니다.
$ echo "${@:1:$#-1}"
0wer 1wdfg 2erty 333 4ffff
물론 매개변수는 다음과 같이 설정할 수도 있습니다.
$ set -- "${@:1:$#-1}"
$ echo $@
0wer 1wdfg 2erty 333 4ffff
이는 bash 2.0 이상에서 작동합니다.
다른 간단한 쉘의 경우 마지막 인수를 제거하려면 (다소 까다로운) 루프가 필요합니다.
unset b; for a; do set -- "$@" ${b+"$b"}; shift; b="$a"; done
답변2
간단히 인수 수를 확인하고 이를 역순으로 처리할 수 있습니다. 예를 들어 인수가 두 개인 경우첫 번째매개변수는 선택사항입니다.
usage() {
cat << EOF
Usage: $0 [host] port
EOF
}
[ "$#" -eq 0 ] && { usage; exit 1;}
if [ "$#" -gt 1 ]; then
myhost="$1"
shift
fi
myport="$1"
그런데 세 가지 매개변수에 대한 아이디어도 언급하셨는데요. 위치적으로 결정된 세 개의 선택적 매개변수를 갖는 것은 결코 작은 일이 아닙니다. 두 번째 대신 첫 번째와 세 번째를 지정하려면 어떻게 해야 합니까? 이 상황은 위치 매개변수만으로는 처리가 거의 불가능하지만 올바르게 사용하면 getopts
.
usage() {
cat << EOF
usage: $0 [OPTIONS]
-p port number (required)
-h hostname (optional)
EOF
}
while getopts :p:h: opt; do
case "$opt" in
p)
myport="$OPTARG"
;;
h)
myhost="$OPTARG"
;;
:)
printf %s\\n "Argument required for option -$OPTARG" >&2
usage >&2
exit 1
;;
\?)
printf %s\\n "Unknown option -$OPTARG" >&2
usage >&2
exit 1
;;
esac
done
shift "$((OPTIND-1))"
if [ -z "$myport" ]; then
printf %s\\n "You must supply a port" >&2
usage >&2
exit 1
fi
답변3
내 질문으로 돌아가서 오늘은 별도의 배열을 사용하여 간단히 구현하고 다음과 같이 전달된 인수 수를 확인할 수 있습니다.
# Just a demo of a command that "shifts right"
# Usage: url_builder [[[scheme] hostname] port]
url_builder() {
local parts=(http localhost 80) # defaults
if (( $# == 3 )); then
parts[0]=$1; shift
fi
if (( $# == 2 )); then
parts[1]=$1; shift
fi
if (( $# == 1 )); then
parts[2]=$1; shift
fi
printf '%s://%s:%s\n' "${parts[@]}"
}
용법:
$ url_builder
http://localhost:80
$ url_builder 100
http://localhost:100
$ url_builder example.com 100
http://example.com:100
$ url_builder ftp example.com 100
ftp://example.com:100
이것이 user79743이 제안한 접근 방식보다 나은지 여부는 set
사용 사례에 따라 다를 수 있지만 매개 변수가 몇 개 이상인 경우 처음에는 이 패턴에 회의적이기 시작합니다. 사용자는 아래와 같이 왼쪽에 선택적으로 표시되는 위치 매개변수가 많은 명령에 다소 놀랄 수 있습니다.