script - shell sh
Obteniendo el último argumento pasado a un script de shell (26)
Aquí está la solución mía:
- bastante portátil (todo POSIX sh, bash, ksh, zsh) debería funcionar
- no desplaza los argumentos originales (desplaza una copia).
- no usa el
maleval
- no itera a través de toda la lista
- no utiliza herramientas externas
Código:
ntharg() {
shift $1
printf ''%s/n'' "$1"
}
LAST_ARG=`ntharg $# "$@"`
$1
es el primer argumento.
$@
son todos ellos.
¿Cómo puedo encontrar el último argumento pasado a un script de shell?
Después de leer las respuestas anteriores, escribí un script de shell Q&D (debería funcionar en sh y bash) para ejecutar g ++ en PGM.cpp para producir una imagen ejecutable PGM. Se supone 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
Encontré esto cuando se busca separar el último argumento de todos los anteriores. Si bien algunas de las respuestas obtienen el último argumento, no son de mucha ayuda si también necesita todos los otros argumentos. Esto funciona mucho mejor:
heads=${@:1:$(($# - 1))}
tail=${@:$#}
Encontré la respuesta de @AgileZebra (más el comentario de @ Starfry) la más útil, pero pone heads
a un escalar. Una matriz es probablemente más útil:
heads=( "${@:1:$(($# - 1))}" )
tail=${@:${#@}}
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. (incluir N), -1 es el último.
Esto es parte de mi función de copia:
eval echo $(echo ''$''"$#")
Para usar en scripts, haga esto:
a=$(eval echo $(echo ''$''"$#"))
Explicación (la más anidada primero):
-
$(echo ''$''"$#")
devuelve$[nr]
donde[nr]
es el número de parámetros. Por ejemplo, la cadena$123
(sin dilatar). -
echo $123
devuelve el valor del parámetro 123, cuando se evalúa. -
eval
simplemente expande$123
al valor del parámetro, por ejemplo,last_arg
. Esto se interpreta como una cadena y se devuelve.
Trabaja con Bash desde mediados de 2015.
Esto es solo Bash:
echo "${@: -1}"
Esto es un poco de un hack:
for last; do true; done
echo $last
Este también es bastante portátil (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
los bucles implícitamente sobre los argumentos si no le dices qué bucear, y el hecho de que las variables de bucle no están dentro del alcance: conservan el último valor en el que se establecieron.
Esto funciona en todos los shells compatibles con POSIX:
eval last=/${$#}
Hay una manera mucho más concisa de hacer esto. Los argumentos de una secuencia de comandos bash se pueden incluir en una matriz, lo que simplifica mucho el manejo de los elementos. La siguiente secuencia de comandos siempre imprimirá el último argumento pasado a una secuencia de comandos.
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]}
Salida de muestra
$ ./lastarg.sh 1 2 buckle my shoe
shoe
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
Lo siguiente establecerá LAST
en el último argumento sin cambiar el entorno actual:
LAST=$({
shift $(($#-1))
echo $1
})
echo $LAST
Si otros argumentos ya no son necesarios y se pueden cambiar, se puede simplificar para:
shift $(($#-1))
echo $1
Por razones de portabilidad siguientes:
shift $(($#-1));
puede ser reemplazado con:
shift `expr $# - 1`
Reemplazando también $()
con backquotes obtenemos:
LAST=`{
shift /`expr $# - 1/`
echo $1
}`
echo $LAST
Lo siguiente funcionará para usted. La @ es para la 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
Para bash
, este comentario sugería lo muy elegante:
echo "${@:$#}"
Para ksh, zsh y bash:
$ set -- The quick brown fox jumps over the lazy dog
$ echo "${@:~0}"
dog
Y para "next to last":
$ echo "${@:~1:1}"
lazy
Para solucionar cualquier problema con los argumentos que comienzan con un guión (como -n
) use:
$ printf ''%s/n'' "${@:~0}"
dog
Y la forma correcta de tratar con espacios y caracteres globales en sh
es:
$ set -- The quick brown fox jumps over the lazy dog "the * last argument"
$ eval echo "/"/${$#}/""
The last * argument
O bien, si desea establecer una last
var:
$ eval last=/${$#}; echo "$last"
The last * argument
Y para "next to last":
$ eval echo "/"/${$(($#-1))}/""
dog
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.
Pruebe el siguiente script 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.
Si está utilizando Bash> = 3.0
echo ${BASH_ARGV[0]}
Si quieres hacerlo de una manera no destructiva, una forma es pasar todos los argumentos a una función y devolver el último:
#!/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 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 nunca querrías mantener los otros argumentos a menos que ya hayan sido procesados. en cuyo caso utilizaría el método process / shift / process / shift / ... para procesarlos secuencialmente.
Supongo que aquí desea conservarlas porque no ha seguido el método secuencial. Este método también maneja el caso donde no hay argumentos, devolviendo "". Puede ajustar fácilmente ese comportamiento insertando la cláusula else
comentada.
Una solución utilizando eval
:
last=$(eval "echo /$$#")
echo $last
Usando la expansión de parámetros (eliminar el inicio coincidente):
args="$@"
last=${args##* }
También es fácil conseguir todo antes de lo último:
prelast=${args% *}
Utilice la indexación combinada con la longitud de:
echo ${@:${#@}}
#! /bin/sh
next=$1
while [ -n "${next}" ] ; do
last=$next
shift
next=$1
done
echo $last
$ 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 .
echo $argv[$#argv]
Ahora solo necesito agregar un poco de texto porque mi respuesta fue demasiado corta para publicar. Necesito añadir más texto para editar.
shift `expr $# - 1`
echo "$1"
Esto desplaza 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 también debería funcionar en sh y ksh.