Obtener el último argumento pasado a un script de shell

$1 es el primer argumento.
$@ es todos ellos.

¿Cómo puedo encontrar el último argumento pasado a un script de shell?

Esto es un poco complicado:

 for last; do true; done echo $last 

Este también es bastante portable (de nuevo, debería funcionar con bash, ksh y sh) y no cambia los argumentos, lo que podría ser bueno.

Utiliza el hecho de que, for bucles implícitos sobre los argumentos, si no le dice en qué bucle, y el hecho de que para las variables de bucle no tienen un ámbito: conservan el último valor en el que se establecieron.

Esto es solo Bash:

 echo "${@: -1}" 

La respuesta más simple para bash 3.0 o superior es

 _last=${!#} # *indirect reference* to the $# variable # or _last=$BASH_ARGV # official built-in (but takes more typing :) 

Eso es.

 $ cat lastarg #!/bin/bash # echo the last arg given: _last=${!#} echo $_last _last=$BASH_ARGV echo $_last for x; do echo $x done 

La salida es:

 $ 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 

El espacio es necesario para que no se interprete como un valor predeterminado .

Utilice la indexación combinada con la duración de:

 echo ${@:${#@}} 

Lo siguiente funcionará para ti. El @ es para una matriz de argumentos. : significa en. $ # es la longitud de la matriz de argumentos. Entonces el resultado es el último elemento:

 ${@:$#} 

Ejemplo:

 function afunction{ echo ${@:$#} } afunction -d -o local 50 #Outputs 50 

Encontrado esto cuando se busca separar el último argumento de todos los anteriores. Si bien algunas de las respuestas tienen el último argumento, no son de mucha ayuda si también necesitas todas las otras discusiones. Esto funciona mucho mejor:

 heads=${@:1:$(($# - 1))} tail=${@:$#} 

Esto funciona en todos los shells compatibles con POSIX:

 eval last=\${$#} 

Fuente: http://www.faqs.org/faqs/unix-faq/faq/part2/section-12.html

Si está utilizando Bash> = 3.0

 echo ${BASH_ARGV[0]} 

Aquí está la solución mía:

  • bastante portátil (todo POSIX sh, bash, ksh, zsh) debería funcionar
  • no cambia los argumentos originales (desplaza una copia).
  • no usa eval malvado
  • no itera a través de toda la lista
  • no usa herramientas externas

Código:

 ntharg() { shift $1 printf '%s\n' "$1" } LAST_ARG=`ntharg $# "$@"` 
 shift `expr $# - 1` echo "$1" 

Esto cambia los argumentos por el número de argumentos menos 1, y devuelve el primer (y único) argumento restante, que será el último.

Solo probé en bash, pero debería funcionar en sh y ksh también.

Si desea hacerlo de una manera no destructiva, una forma es pasar todos los argumentos a una función y devolver la última:

 #!/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 realmente no te importa mantener los otros argumentos, no lo necesitas en una función, pero me cuesta pensar en una situación en la que no quieras guardar los otros argumentos a menos que ya hayan sido procesados, en cuyo caso usaría el método process / shift / process / shift / … para procesarlos secuencialmente.

Supongo que quieres conservarlos porque no has seguido el método secuencial. Este método también maneja el caso donde no hay argumentos y devuelve “”. Puede ajustar fácilmente ese comportamiento insertando la cláusula else comentada.

Para tcsh:

 set X = `echo $* | awk -F " " '{print $NF}'` somecommand "$X" 

Estoy bastante seguro de que esta sería una solución portátil, a excepción de la asignación.

Una solución que usa eval :

 last=$(eval "echo \$$#") echo $last 

Después de leer las respuestas anteriores, escribí un guión de shell de Q & D (debería trabajar en sh y bash) para ejecutar g ++ en PGM.cpp para producir PGM de imagen ejecutable. Asume que el último argumento en la línea de comando es el nombre del archivo (.cpp es opcional) y todos los demás argumentos son opciones.

 #!/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 

Lo siguiente establecerá LAST en el último argumento sin cambiar el entorno actual:

 LAST=$({ shift $(($#-1)) echo $1 }) echo $LAST 

Si ya no se necesitan otros argumentos y se pueden cambiar, se puede simplificar a:

 shift $(($#-1)) echo $1 

Por razones de portabilidad siguientes:

 shift $(($#-1)); 

puede ser reemplazado por:

 shift `expr $# - 1` 

Reemplazando también $() con las comillas inversas obtenemos:

 LAST=`{ shift \`expr $# - 1\` echo $1 }` echo $LAST 
 echo $argv[$#argv] 

Ahora solo necesito agregar texto porque mi respuesta fue demasiado corta para publicarla. Necesito agregar más texto para editar.

Encontré la respuesta de @ AgileZebra (más el comentario de @ starfry) la más útil, pero establece las heads en un escalar. Una matriz es probablemente más útil:

 heads=( "${@:1:$(($# - 1))}" ) tail=${@:${#@}} 

Para ksh, zsh y bash:

 $ set -- The quick brown fox jumps over the lazy dog $ echo "${@:~0}" dog 

Y para “el penúltimo”:

 $ echo "${@:~1:1}" lazy 

Para solucionar cualquier problema con los argumentos que comiencen con un guion (como -n ) use:

 $ printf '%s\n' "${@:~0}" dog 

Y la forma correcta de tratar con espacios y personajes glob en sh es:

 $ set -- The quick brown fox jumps over the lazy dog "the * last argument" $ eval echo "\"\${$#}\"" The last * argument 

O bien, si quieres establecer una last var:

 $ eval last=\${$#}; echo "$last" The last * argument 

Y para “el penúltimo”:

 $ eval echo "\"\${$(($#-1))}\"" dog 
 #! /bin/sh next=$1 while [ -n "${next}" ] ; do last=$next shift next=$1 done echo $last 

Esto es parte de mi función de copia:

 eval echo $(echo '$'"$#") 

Para usar en scripts, haz esto:

 a=$(eval echo $(echo '$'"$#")) 

Explicación (la mayoría anidada primero):

  1. $(echo '$'"$#") devuelve $[nr] donde [nr] es el número de parámetros. Por ejemplo, la cadena $123 (sin expandir).
  2. echo $123 devuelve el valor del parámetro 123rd, cuando se evalúa.
  3. eval solo expande $123 al valor del parámetro, por last_arg . last_arg . Esto se interpreta como una cadena y se devuelve.

Funciona con Bash a mediados de 2015.

Pruebe la siguiente secuencia de comandos para encontrar el último argumento

  # 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 

Salida:

  # ./arguments.sh No Arguments supplied # ./arguments.sh testing for the last argument value Last Argument is: value 

Gracias.

Hay una forma mucho más concisa de hacer esto. Los argumentos de una secuencia de comandos bash se pueden incorporar a una matriz, lo que hace que manejar los elementos sea mucho más simple. El script a continuación siempre imprimirá el último argumento pasado a 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]} 

Muestra de salida

 $ ./lastarg.sh 1 2 buckle my shoe shoe 

Este formato puede funcionar en Slackware y Cygwin.

“$ {x [@]: (- 1)}”, si se usa con $ @, “$ {@: (- 1)}”

Significa que es: $ {@ 🙁 N)}, devolverá todos los elementos después del índice N. (incluya N), -1 es el último.

Uso de la expansión de parámetros (eliminar el inicio coincidente):

 args="$@" last=${args##* } 

También es fácil obtener todo antes del último:

 prelast=${args% *}