$1
est le premier argument.
$@
est tout.
Comment trouver le dernier argument transmis à un script shell?
C’est un peu un hack:
for last; do true; done echo $last
Celui-ci est également assez portable (encore une fois, cela devrait fonctionner avec bash, ksh et sh) et cela ne décale pas les arguments, ce qui pourrait être intéressant.
Il utilise le fait que for
boucles implicitement sur les arguments si vous ne lui dites pas ce qu’il faut parcourir, et le fait que pour les variables de boucle ne sont pas définis: ils conservent la dernière valeur à laquelle ils ont été définis.
Ceci est Bash-only:
echo "${@: -1}"
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 tout.
$ cat lastarg #!/bin/bash # echo the last arg given: _last=${!#} echo $_last _last=$BASH_ARGV echo $_last for x; do echo $x done
Le résultat est:
$ lastarg 1 2 3 4 "5 6 7" 5 6 7 5 6 7 1 2 3 4 5 6 7
$ 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 une valeur par défaut .
Utiliser l’indexation combinée avec la longueur de:
echo ${@:${#@}}
Ce qui suit fonctionnera pour vous. Le @ est un tableau d’arguments. : signifie à. $ # est la longueur du tableau d’arguments. Le résultat est donc le dernier élément:
${@:$#}
Exemple:
function afunction{ echo ${@:$#} } afunction -d -o local 50 #Outputs 50
Vous l’avez trouvé en cherchant à séparer le dernier argument de tous les précédents. Bien que certaines des réponses obtiennent le dernier argument, elles ne sont pas très utiles si vous avez également besoin de tous les 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
Si vous utilisez Bash> = 3.0
echo ${BASH_ARGV[0]}
Voici la solution:
eval
Code:
ntharg() { shift $1 printf '%s\n' "$1" } LAST_ARG=`ntharg $# "$@"`
shift `expr $# - 1` echo "$1"
Cela décale les arguments du nombre d’arguments moins 1 et renvoie le premier (et seul) argument restant, qui sera le dernier.
J’ai seulement testé en bash, mais ça devrait fonctionner aussi bien en sh qu’en ksh.
Si vous voulez le faire de manière non destructive, vous pouvez passer 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 ab b 1 2 3 ab
Si vous ne vous souciez pas vraiment de conserver les autres arguments, vous n’en avez pas besoin dans une fonction, mais j’ai du mal à penser à une situation où vous ne voudriez jamais conserver les autres arguments à moins qu’ils aient déjà été traités. Dans ce cas, j’utiliserais la méthode process / shift / process / shift / … pour les traiter séquentiellement.
Je suppose que vous voulez les conserver car 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’arguments, en retournant “”. Vous pouvez facilement ajuster ce comportement en insérant la clause else
commentée.
Pour tcsh:
set X = `echo $* | awk -F " " '{print $NF}'` somecommand "$X"
Je suis sûr que ce serait une solution portable, à l’exception de la mission.
Une solution utilisant eval
:
last=$(eval "echo \$$#") echo $last
Après avoir lu les réponses ci-dessus, j’ai écrit un script shell Q & D (devrait fonctionner sur sh et bash) pour exécuter g ++ sur PGM.cpp afin de produire une image PGM exécutable. 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 comstack 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
Ce qui suit définit le dernier argument sans modifier 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, il peut être simplifié pour:
shift $(($#-1)) echo $1
Pour des raisons de portabilité suivantes:
shift $(($#-1));
peut être remplacé par:
shift `expr $# - 1`
En remplaçant aussi $()
par des backquotes, nous obtenons:
LAST=`{ shift \`expr $# - 1\` echo $1 }` echo $LAST
echo $argv[$#argv]
Maintenant, j’ai juste besoin d’append du texte car ma réponse était trop courte pour poster. Je dois append plus de texte à modifier.
J’ai trouvé la réponse de @AgileZebra (le commentaire de plus @ starfry) la plus utile, mais elle place les heads
dans un scalaire. Un tableau est probablement plus utile:
heads=( "${@:1:$(($# - 1))}" ) tail=${@:${#@}}
Pour ksh, zsh et bash:
$ set -- The quick brown fox jumps over the lazy dog $ echo "${@:~0}" dog
Et pour “next to last”:
$ echo "${@:~1:1}" lazy
Pour contourner tous les problèmes avec des 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:
$ set -- The quick brown fox jumps over the lazy dog "the * last argument" $ eval echo "\"\${$#}\"" The last * argument
Ou, si vous voulez définir un last
var:
$ eval last=\${$#}; echo "$last" The last * argument
Et pour “next to last”:
$ eval echo "\"\${$(($#-1))}\"" dog
#! /bin/sh next=$1 while [ -n "${next}" ] ; do last=$next shift next=$1 done echo $last
Ceci fait partie de ma fonction de copie:
eval echo $(echo '$'"$#")
Pour utiliser dans les scripts, procédez comme suit:
a=$(eval echo $(echo '$'"$#"))
Explication (le plus nested en premier):
$(echo '$'"$#")
renvoie $[nr]
où [nr]
est le nombre de parameters. Par exemple la chaîne $123
(non expansée). echo $123
renvoie la valeur du paramètre 123rd, lorsqu’il est évalué. eval
développe simplement $123
à la valeur du paramètre, par exemple last_arg
. Ceci est interprété comme une chaîne et renvoyé. Fonctionne avec Bash dès la mi-2015.
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.
Il existe un moyen beaucoup plus concis de le faire. Les arguments pour un script bash peuvent être placés dans un tableau, ce qui simplifie 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]}
Sortie de l’échantillon
$ ./lastarg.sh 1 2 buckle my shoe shoe
Ce format peut fonctionner dans Slackware et Cygwin.
“$ {x [@]: (- 1)}”, si utilisé avec $ @, “$ {@: (- 1)}”
Cela signifie que: $ {@ 🙁 N)}, renverra tous les éléments après l’index N. (inclure N), -1 est le dernier.
Utilisation de l’extension de paramètre (supprimer le début correspondant):
args="$@" last=${args##* }
Il est également facile de tout obtenir avant la fin:
prelast=${args% *}