Development Tip

"$ @"의 마지막 매개 변수 앞의 매개 변수 추출

yourdevel 2020. 11. 26. 19:57
반응형

"$ @"의 마지막 매개 변수 앞의 매개 변수 추출


명령 줄에서 주어진 마지막 매개 변수를 다른 곳에서 사용할 변수로 추출하는 Bash 스크립트를 만들려고합니다. 내가 작업중인 스크립트는 다음과 같습니다.

#!/bin/bash
# compact - archive and compact file/folder(s)

eval LAST=\$$#

FILES="$@"
NAME=$LAST

# Usage - display usage if no parameters are given
if [[ -z $NAME ]]; then
  echo "compact <file> <folder>... <compressed-name>.tar.gz"
  exit
fi

# Check if an archive name has been given
if [[ -f $NAME ]]; then
  echo "File exists or you forgot to enter a filename.  Exiting."
  exit
fi

tar -czvpf "$NAME".tar.gz $FILES

첫 번째 매개 변수는 숫자가 될 수 있으므로 마지막 매개 변수를 추출하는 방법을 찾아야합니다 (예 : compact file.a file.b file.d files-abd.tar.gz). 이제 압축 할 파일에 아카이브 이름이 포함됩니다. 이를 수행하는 방법이 있습니까?


배열에서 마지막 항목을 제거하려면 다음과 같이 사용할 수 있습니다.

#!/bin/bash

length=$(($#-1))
array=${@:1:$length}
echo $array

더 짧은 방법 :

array=${@:1:$#-1}

그러나 arays는 Bashism 입니다.


last_arg="${!#}" 

휴대용 소형 솔루션

이것이 내 스크립트에서 수행하는 방법입니다.

last=${@:$#} # last parameter 
other=${*%${!#}} # all parameters except the last

편집
일부 의견 (아래 참조)에 따르면이 솔루션은 다른 솔루션보다 이식성이 뛰어납니다.
작동 방식에 대한 설명은 Michael Dimmitt의 주석을 읽어보십시오.


여러 솔루션이 이미 게시되었습니다. 그러나 아카이브 이름이 마지막 매개 변수가 아닌 첫 번째 매개 변수 가되도록 스크립트를 재구성하는 것이 좋습니다. 그러면 shift내장사용 하여 첫 번째 매개 변수를 제거 할 수 있으므로 매우 간단합니다 .

ARCHIVENAME="$1"
shift
# Now "$@" contains all of the arguments except for the first

감사합니다. 완료되었습니다. 여기에 최종 bash 스크립트가 있습니다.

#!/bin/bash
# compact - archive and compress file/folder(s)

# Extract archive filename for variable
ARCHIVENAME="${!#}"

# Remove archive filename for file/folder list to backup
length=$(($#-1))
FILES=${@:1:$length} 

# Usage - display usage if no parameters are given
if [[ -z $@ ]]; then
  echo "compact <file> <folder>... <compressed-name>.tar.gz"
  exit
fi

# Tar the files, name archive after last file/folder if no name given
if [[ ! -f $ARCHIVENAME ]]; then
  tar -czvpf "$ARCHIVENAME".tar.gz $FILES; else
  tar -czvpf "$ARCHIVENAME".tar.gz "$@"
fi

lengthKrzysztof Klimonda의 솔루션에 사용 된 변수를 삭제하면 됩니다.

(
set -- 1 2 3 4 5
echo "${@:1:($#-1)}"       # 1 2 3 4
echo "${@:(-$#):($#-1)}"   # 1 2 3 4
)

나는 이것을 코멘트로 추가하고 싶지만 평판이 충분하지 않아 어쨌든 대답이 조금 더 길어졌습니다. 신경 쓰지 않기를 바랍니다.

@func가 말했듯이 :

last_arg = "$ {! #}"

작동 원리 :

$ {! PARAM} 은 간접 수준을 나타냅니다. 당신이 참조되지 않은 PARAM 자체 만에 저장된 값 PARAM은 (생각 PARAM 값 포인터로).
$ {#} 는 매개 변수 수로 확장됩니다 (참고 : $ 0- 스크립트 이름-여기에서는 계산되지 않음).

다음 실행을 고려하십시오.

$./myscript.sh p1 p2 p3

그리고 myscript.sh에서

#!/bin/bash

echo "Number of params: ${#}"  # 3
echo "Last parameter using '\${!#}': ${!#}"  # p3
echo "Last parameter by evaluating positional value: $(eval LASTP='$'${#} ; echo $LASTP)"  # p3

따라서 $ {! #} 를 위의 평가 사용에 대한 바로 가기로 생각할 수 있습니다 . 위의 방법을 정확히 수행합니다. 주어진 매개 변수에 저장된 값을 평가합니다. 여기서 매개 변수는 3 이고 위치 인수 $ 3을 보유합니다.

이제 마지막 매개 변수를 제외한 모든 매개 변수를 원하는 경우 하위 문자열 제거 $ {PARAM % PATTERN}을 사용할 수 있습니다. 여기서 % 기호는 '문자열 끝에서 가장 짧은 일치 패턴 제거'를 의미 합니다 .

따라서 스크립트에서 :

echo "Every parameter except the last one: ${*%${!#}}"


여기에서 읽을 수 있습니다 : 매개 변수 확장


#!/bin/bash

lastidx=$#
lastidx=`expr $lastidx - 1`

eval last='$'{$lastidx}
echo $last

이 멋진 스크립트가 tar의 단순한 별칭보다 낫다고 확신합니까?

alias compact="tar -czvpf"

사용법은 다음과 같습니다.

compact ARCHIVENAME FILES...

FILES는 다음 file1 file2과 같거나 glob 일 수 있습니다.*.html


시험:

if [ "$#" -gt '0' ]; then
    /bin/echo "${!#}" "${@:1:$(($# - 1))}
fi

마지막 매개 변수가없는 배열 :

array=${@:1:$#-1}

그러나 그것은 bashism입니다 :(. 적절한 솔루션은 다른 사람들이 사용하는 것처럼 변수에 이동하고 추가하는 것을 포함합니다.


인수 목록에서 마지막 매개 변수를 가져 오는 다른 방법 :

eval last="\$$#"
eval set -- `awk 'BEGIN{for(i=1;i<'$#';i++) printf " \"$%d\"",i;}'`

#! / bin / sh

eval last = '$'$ #
테스트하는 동안 $ # -gt 1; 하다
    list = "$ list $ 1"
    시프트
끝난

echo $ list $ last


에서 배열 첨자 표기법을 사용하는 방법을 찾을 수 $@없으므로 이것이 내가 할 수있는 최선의 방법입니다.

#!/bin/bash

args=("$@")
echo "${args[$(($#-1))]}"

이 스크립트는 사용자에게 적합 할 수 있습니다. 인수의 하위 범위를 반환하고 다른 스크립트에서 호출 할 수 있습니다.

실행 예 :

$ args_get_range 2 -2 y a b "c 1" d e f g                          
'b' 'c 1' 'd' 'e'

$ args_get_range 1 2 n arg1 arg2                                   
arg1 arg2

$ args_get_range 2 -2 y arg1 arg2 arg3 "arg 4" arg5                
'arg2' 'arg3'

$ args_get_range 2 -1 y arg1 arg2 arg3 "arg 4" arg5                
'arg2' 'arg3' 'arg 4'

# You could use this in another script of course 
# by calling it like so, which puts all
# args except the last one into a new variable
# called NEW_ARGS

NEW_ARGS=$(args_get_range 1 -1 y "$@")

args_get_range.sh

#!/usr/bin/env bash

function show_help()
{
  IT="
  Extracts a range of arguments from passed in args
  and returns them quoted or not quoted.

  usage: START END QUOTED ARG1 {ARG2} ...

  e.g. 

  # extract args 2-3 
  $ args_get_range.sh 2 3 n arg1 arg2 arg3
  arg2 arg3

  # extract all args from 2 to one before the last argument 
  $ args_get_range.sh 2 -1 n arg1 arg2 arg3 arg4 arg5
  arg2 arg3 arg4

  # extract all args from 2 to 3, quoting them in the response
  $ args_get_range.sh 2 3 y arg1 arg2 arg3 arg4 arg5
  'arg2' 'arg3'

  # You could use this in another script of course 
  # by calling it like so, which puts all
  # args except the last one into a new variable
  # called NEW_ARGS

  NEW_ARGS=\$(args_get_range.sh 1 -1 \"\$@\")

  "
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ $# -lt 3 ]
then
  show_help
fi

START=$1
END=$2
QUOTED=$3
shift;
shift;
shift;

if [ $# -eq 0 ]
then
  echo "Please supply a folder name"
  exit;
fi

# If end is a negative, it means relative
# to the last argument.
if [ $END -lt 0 ]
then
  END=$(($#+$END))
fi

ARGS=""

COUNT=$(($START-1))
for i in "${@:$START}"
do
  COUNT=$((COUNT+1))

  if [ "$QUOTED" == "y" ]
  then
    ARGS="$ARGS '$i'"
  else
    ARGS="$ARGS $i"
  fi

  if [ $COUNT -eq $END ]
  then
    echo $ARGS
    exit;
  fi
done
echo $ARGS

참고 URL : https://stackoverflow.com/questions/1215538/extract-parameters-before-last-parameter-in

반응형