$1
est le premier argument.$@
sont tous.
Comment trouver le dernier argument transmis à un script shell?
C'est un peu un bidouillage:
for last; do true; done
echo $last
Celui-ci est également assez portable (encore une fois, devrait fonctionner avec bash, ksh et sh) et il ne décale pas les arguments, ce qui pourrait être Nice.
Il utilise le fait que for
boucle implicitement sur les arguments si vous ne lui indiquez pas ce qu'il faut faire suivre en boucle, et le fait que les variables de boucle for ne sont pas étendues: elles conservent la dernière valeur à laquelle elles ont été définies.
Ceci est uniquement Bash:
echo "${@: -1}"
$ set quick brown fox jumps
$ echo ${*: -1:1} # last argument
jumps
$ echo ${*: -1} # or simply
jumps
$ echo ${*: -2:1} # next to last
fox
L'espace est nécessaire pour qu'il ne soit pas interprété comme un valeur par défaut .
La réponse la plus simple pour bash 3.0 ou supérieur est
_last=${!#} # *indirect reference* to the $# variable
# or
_last=$BASH_ARGV # official built-in (but takes more typing :)
C'est ça.
$ cat lastarg
#!/bin/bash
# echo the last arg given:
_last=${!#}
echo $_last
_last=$BASH_ARGV
echo $_last
for x; do
echo $x
done
La sortie est:
$ lastarg 1 2 3 4 "5 6 7"
5 6 7
5 6 7
1
2
3
4
5 6 7
Utilisez l'indexation combinée avec la longueur de:
echo ${@:${#@}}
Ce qui suit fonctionnera pour vous. Le @ est pour tableau d'arguments. : signifie à. $ # est la longueur du tableau d'arguments. Donc, le résultat est le dernier élément:
${@:$#}
Exemple:
function afunction{
echo ${@:$#}
}
afunction -d -o local 50
#Outputs 50
Trouvé ceci en cherchant à séparer le dernier argument de tous les précédents. Bien que certaines réponses obtiennent le dernier argument, elles ne sont pas d'une grande aide si vous avez également besoin de tous les autres arguments. Cela fonctionne beaucoup mieux:
heads=${@:1:$(($# - 1))}
tail=${@:$#}
Cela fonctionne dans tous les shells compatibles POSIX:
eval last=\${$#}
Source: http://www.faqs.org/faqs/unix-faq/faq/part2/section-12.html
Voici ma solution:
eval
Code:
ntharg() {
shift $1
printf '%s\n' "$1"
}
LAST_ARG=`ntharg $# "$@"`
Si vous utilisez Bash> = 3.0
echo ${BASH_ARGV[0]}
Pour ksh, zsh et bash:
$ set -- The quick brown fox jumps over the lazy dog
$ echo "${@:~0}"
dog
Et pour "l'avant dernier":
$ echo "${@:~1:1}"
lazy
Pour résoudre les problèmes d'arguments commençant par un tiret (comme -n
), utilisez:
$ printf '%s\n' "${@:~0}"
dog
Et la manière correcte de traiter les espaces et les caractères globaux dans sh
est la suivante:
$ set -- The quick brown fox jumps over the lazy dog "the * last argument"
$ eval echo "\"\${$#}\""
The last * argument
Ou, si vous souhaitez définir une variable last
var:
$ eval last=\${$#}; echo "$last"
The last * argument
Et pour "l'avant dernier":
$ eval echo "\"\${$(($#-1))}\""
dog
shift `expr $# - 1`
echo "$1"
Cela décale les arguments du nombre d'arguments moins 1 et renvoie le premier (et le seul) argument restant, qui sera le dernier.
Je n'ai testé que bash, mais cela devrait fonctionner également avec sh et ksh.
Si vous voulez le faire de manière non destructive, une solution consiste à transmettre tous les arguments à une fonction et à renvoyer le dernier:
#!/bin/bash
last() {
if [[ $# -ne 0 ]] ; then
shift $(expr $# - 1)
echo "$1"
#else
#do something when no arguments
fi
}
lastvar=$(last "$@")
echo $lastvar
echo "$@"
pax> ./qq.sh 1 2 3 a b
b
1 2 3 a b
Si vous ne tenez pas attention sur la conservation des autres arguments, vous n'en avez pas besoin dans une fonction, mais j'ai du mal à penser à une situation dans laquelle vous ne voudriez jamais conserver les autres arguments à moins que ils ont déjà été traités, auquel cas j'utiliserais la méthode process/shift/process/shift/... pour les traiter séquentiellement.
Je suppose ici que vous voulez les conserver parce que vous n'avez pas suivi la méthode séquentielle. Cette méthode gère également le cas où il n'y a pas d'argument, renvoyant "". Vous pouvez facilement ajuster ce comportement en insérant la clause commentée else
.
Pour tcsh:
set X = `echo $* | awk -F " " '{print $NF}'`
somecommand "$X"
Je suis à peu près sûr que ce serait une solution portable, sauf pour la mission.
Pour bash
, ce commentaire a suggéré le très élégant:
echo "${@:$#}"
En prime, cela fonctionne également dans zsh
.
Ce qui suit va définir LAST
sur le dernier argument sans changer l'environnement actuel:
LAST=$({
shift $(($#-1))
echo $1
})
echo $LAST
Si d'autres arguments ne sont plus nécessaires et peuvent être déplacés, vous pouvez le simplifier pour:
shift $(($#-1))
echo $1
Pour des raisons de portabilité suivantes:
shift $(($#-1));
peut être remplacé par:
shift `expr $# - 1`
En remplaçant également $()
par des citations arrières, nous obtenons:
LAST=`{
shift \`expr $# - 1\`
echo $1
}`
echo $LAST
Une solution utilisant eval
:
last=$(eval "echo \$$#")
echo $last
Cela fait partie de ma fonction de copie:
eval echo $(echo '$'"$#")
Pour utiliser dans les scripts, procédez comme suit:
a=$(eval echo $(echo '$'"$#"))
Explication (la plus imbriquée en premier):
$(echo '$'"$#")
renvoie $[nr]
où [nr]
est le nombre de paramètres. Par exemple. la chaîne $123
(non développée).echo $123
renvoie la valeur du paramètre 123rd, une fois évalué.eval
étend simplement $123
à la valeur du paramètre, par exemple. last_arg
. Ceci est interprété comme une chaîne et renvoyé.Fonctionne avec Bash à partir de mi-2015.
Après avoir lu les réponses ci-dessus, j’ai écrit un script Q & D Shell (qui devrait fonctionner sous sh et bash) pour exécuter g ++ sur PGM.cpp afin de produire une image exécutable PGM. Il suppose que le dernier argument de la ligne de commande est le nom du fichier (.cpp est facultatif) et que tous les autres arguments sont des options.
#!/bin/sh
if [ $# -lt 1 ]
then
echo "Usage: `basename $0` [opt] pgm runs g++ to compile pgm[.cpp] into pgm"
exit 2
fi
OPT=
PGM=
# PGM is the last argument, all others are considered options
for F; do OPT="$OPT $PGM"; PGM=$F; done
DIR=`dirname $PGM`
PGM=`basename $PGM .cpp`
# put -o first so it can be overridden by -o specified in OPT
set -x
g++ -o $DIR/$PGM $OPT $DIR/$PGM.cpp
echo $argv[$#argv]
Maintenant, je dois juste ajouter un texte car ma réponse était trop courte pour être postée. J'ai besoin d'ajouter plus de texte à modifier.
J'ai trouvé la réponse de @ AgileZebra (plus le commentaire de @ starfry) la plus utile, mais elle définit heads
sur un scalaire. Un tableau est probablement plus utile:
heads=( "${@:1:$(($# - 1))}" )
tail=${@:${#@}}
Essayez le script ci-dessous pour trouver le dernier argument
# cat arguments.sh
#!/bin/bash
if [ $# -eq 0 ]
then
echo "No Arguments supplied"
else
echo $* > .ags
sed -e 's/ /\n/g' .ags | tac | head -n1 > .ga
echo "Last Argument is: `cat .ga`"
fi
Sortie:
# ./arguments.sh
No Arguments supplied
# ./arguments.sh testing for the last argument value
Last Argument is: value
Merci.
#! /bin/sh
next=$1
while [ -n "${next}" ] ; do
last=$next
shift
next=$1
done
echo $last
Il y a une manière beaucoup plus concise de faire ceci. Les arguments d'un script bash peuvent être importés dans un tableau, ce qui simplifie beaucoup la gestion des éléments. Le script ci-dessous imprimera toujours le dernier argument transmis à un script.
argArray=( "$@" ) # Add all script arguments to argArray
arrayLength=${#argArray[@]} # Get the length of the array
lastArg=$((arrayLength - 1)) # Arrays are zero based, so last arg is -1
echo ${argArray[$lastArg]}
Échantillon de sortie
$ ./lastarg.sh 1 2 buckle my shoe
shoe
Utilisation de l’expansion des paramètres (début correspondant à la suppression):
args="$@"
last=${args##* }
Il est également facile d'obtenir tout avant dernier:
prelast=${args% *}