recibe - scripts bash ejemplos
Extraiga los parámetros antes del último parámetro en "$ @" (14)
Estoy tratando de crear una secuencia de comandos Bash que extraiga el último parámetro dado de la línea de comandos en una variable que se utilizará en otro lugar. Aquí está el guión en el que estoy trabajando:
#!/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
Dado que los primeros parámetros pueden ser de cualquier número, tengo que encontrar una forma de extraer el último parámetro (por ejemplo, archivo compacto.un archivo.b archivo.d archivos-abd.tar.gz). Como está ahora, el nombre del archivo se incluirá en los archivos para compactar. ¿Hay alguna forma de hacer esto?
Soluciones portátiles y compactas.
Así es como lo hago en mis guiones.
last=${@:$#} # last parameter
other=${*%${!#}} # all parameters except the last
EDITAR
Según algunos comentarios (ver más abajo), esta solución es más portátil que otras.
Por favor, lea el comentario de Michael Dimmitt para una explicación de cómo funciona.
¿Estás seguro de que este elegante script es mejor que un simple alias para tar?
alias compact="tar -czvpf"
El uso es:
compact ARCHIVENAME FILES...
Donde ARCHIVOS pueden ser file1 file2
o globos como *.html
Agregaría esto como un comentario, pero no tengo suficiente reputación y la respuesta se alargó un poco de todos modos. Espero que no le importe.
Como dijo @func:
last_arg = "$ {! #}"
Cómo funciona:
$ {! PARAM} indica el nivel de direccionamiento indirecto. No hace referencia a PARAM en sí, sino al valor almacenado en PARAM (piense en PARAM como puntero a valor).
$ {#} se expande a la cantidad de parámetros (Nota: $ 0 - el nombre del script - no se cuenta aquí).
Considere la siguiente ejecución:
$./myscript.sh p1 p2 p3
Y en el 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
Por lo tanto, puede pensar en $ {! #} Como un atajo para el uso de evaluación anterior, que hace exactamente el enfoque descrito anteriormente: evalúa el valor almacenado en el parámetro dado, aquí el parámetro es 3 y mantiene el argumento posicional $ 3
Ahora, si desea todos los parámetros excepto el último, puede usar la eliminación de la subcadena $ {PARAM% PATTERN}, donde el signo % significa "eliminar el patrón de coincidencia más corto del final de la cadena" .
De ahí en nuestro guión:
echo "Every parameter except the last one: ${*%${!#}}"
Puedes leer algo aquí: Expansión de parámetros
Array sin último parámetro:
array=${@:1:$#-1}
Pero es un bashism :(. Las soluciones adecuadas implicarían el cambio y la adición de variables a medida que otros lo usan.
Este script puede funcionar para usted: devuelve un subrango de los argumentos y puede llamarse desde otro script.
Ejemplos de ello corriendo:
$ 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
Gracias chicos, lo hicieron, aquí está el último guión de 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
No puedo encontrar una manera de usar la notación de subíndice de matriz en $@
, por lo que esta es la mejor que puedo hacer:
#!/bin/bash
args=("$@")
echo "${args[$(($#-1))]}"
Para eliminar el último elemento de la matriz, podría usar algo como esto:
#!/bin/bash
length=$(($#-1))
array=${@:1:$length}
echo $array
Solo eliminando la variable de length
utilizada en la solución de Krzysztof Klimonda:
(
set -- 1 2 3 4 5
echo "${@:1:($#-1)}" # 1 2 3 4
echo "${@:(-$#):($#-1)}" # 1 2 3 4
)
Tratar:
if [ "$#" -gt ''0'' ]; then
/bin/echo "${!#}" "${@:1:$(($# - 1))}
fi
Ya se han publicado varias soluciones; sin embargo, aconsejaría reestructurar su script para que el nombre del archivo sea el primer parámetro en lugar del último. Entonces es realmente sencillo, ya que puedes usar el shift
incorporado para eliminar el primer parámetro:
ARCHIVENAME="$1"
shift
# Now "$@" contains all of the arguments except for the first
#!/bin/bash
lastidx=$#
lastidx=`expr $lastidx - 1`
eval last=''$''{$lastidx}
echo $last
last_arg="${!#}"
#!/bin/sh eval last=''$''$# while test $# -gt 1; do list="$list $1" shift done echo $list $last