web-dev-qa-db-ja.com

「$ @」の最後のパラメーターの前にパラメーターを抽出します

コマンドラインから指定された最後のパラメーターを変数に抽出して他の場所で使用する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

最初のパラメーターは任意の数にすることができるため、最後のパラメーターを抽出する方法を見つける必要があります(例:コンパクトファイル.aファイル.bファイル.dファイル-a-b-d.tar.gz)。現在、アーカイブ名は圧縮するファイルに含まれています。これを行う方法はありますか?

61
user148813

配列から最後の項目を削除するには、次のようなものを使用できます。

#!/bin/bash

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

さらに短い方法:

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

しかしaraysは Bashism なので、それらの使用は避けてください:(。

93
last_arg="${!#}" 
19
func

ポータブルでコンパクトなソリューション

これは私のスクリプトでのやり方です

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

[〜#〜]編集[〜#〜]
一部のコメント(下記参照)によると、このソリューションは他のソリューションよりも移植性が高くなっています。
動作の説明については、Michael Dimmittの解説をご覧ください。

12
ePi272314

いくつかの解決策がすでに投稿されています。ただし、アーカイブ名が最後ではなくfirstパラメータになるようにスクリプトを再構築することをお勧めします。 shift builtin を使用して最初のパラメーターを削除できるため、それは本当に簡単です。

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

皆さん、ありがとうございました。最終的な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
5
user148813

私はこれをコメントとして追加しますが、十分な評判がなく、とにかく答えが少し長くなりました。それが気にならないことを願っています。

@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

したがって、$ {!#}は上記のevalの使用法のショートカットと考えることができます。これは、上記のアプローチを正確に実行します-に格納された値を評価します指定されたパラメータ、ここではパラメータは3であり、位置引数$ 3を保持します

最後のものを除くすべてのパラメータが必要な場合は、部分文字列の削除を使用できます$ {PARAM%PATTERN}where記号はを意味します '最短一致パターンを文字列の末尾から削除します'

したがって、スクリプトでは次のようになります。

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


あなたはここで何かを読むことができます: パラメータ展開

3
CermakM

Krzysztof Klimondaのソリューションで使用されているlength変数を削除するだけです。

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

この派手なスクリプトは、tarの単純なエイリアスよりも優れていますか?

alias compact="tar -czvpf"

使い方は:

compact ARCHIVENAME FILES...

FILESはfile1 file2または*.htmlのようなグロブです。

1
MestreLion

引数リストから最後のパラメーターを引き出す別の方法:

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

最後のパラメータのない配列:

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

しかし、それは bashism :(です。適切な解決策は、シフトと、他のユーザーが使用する変数への追加を含みます。

1
pevik
#!/bin/bash

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

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

試してください:

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

このスクリプトはあなたのために働くかもしれません-それは引数の部分範囲を返し、別のスクリプトから呼び出すことができます。

実行中の例:

$ 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
0
Brad Parks
#!/ bin/sh 
 
 eval last = '$' $#
 while test $#-gt 1; do 
 list = "$ list $ 1" 
 shift 
 done 
 
 echo $ list $ last 
 
0
William Pursell

$@で配列添え字表記を使用する方法が見つからないため、これが私ができる最善の方法です。

#!/bin/bash

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