2010-04-23 22 views
81

Estoy escribiendo un script bash que debe recorrer los argumentos pasados ​​en el script. Sin embargo, el primer argumento no debe buclearse y, en su lugar, debe verificarse antes del ciclo.

Si yo no tuviera que quitar ese primer elemento acabo de poder hacer:

for item in "[email protected]" ; do 
    #process item 
done 

pude modificar el bucle para comprobar si está en su primera iteración y cambiar el comportamiento, pero que parece demasiado hackish. Tiene que haber una manera simple de extraer el primer argumento y luego recorrer el resto, pero no pude encontrarlo.

Respuesta

96

Uso shift?

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_07.html

Básicamente, leer $1 para el primer argumento antes del bucle (o $0 si lo que está queriendo comprobar es el nombre del script), a continuación, utilizar shift, a continuación, un bucle sobre la [email protected] restante.

+5

Mira, yo sabía * * había una respuesta sencilla. :) – Herms

+0

Se merece un voto positivo, pero _después_ las respuestas de Dennis son aceptadas :) – mgarciaisaia

+0

@mgarciaisaia parece más apropiado para los requisitos del OP: * eliminar * el primer elemento –

28
firstitem=$1 
shift; 
for item in "[email protected]" ; do 
    #process item 
done 
+0

Recuerda que '$ 0' es generalmente el nombre del script. – Amber

+2

+1 para mostrar un ejemplo simple; tenga en cuenta que la parte 'in '$ @" 'está implícita y se puede omitir. – mklement0

+0

@ mklement0 ¿Estás diciendo que puedes hacer "por artículo, hacer"? –

91

Otra variación utiliza matriz rebanar:

for item in "${@:2}" 
do 
    process "$item" 
done 

Esto podría ser útil si, por alguna razón, que quería dejar los argumentos en vigor desde shift es destructiva.

+3

Gracias por $ {@: 2}. ¡Buen material! – spesic

+0

Exactamente lo que quería. Ahora no necesita la variable temp para desreferenciar el primer argumento en '" $ {! 1} $ {@: 2} "' –

+0

@Herms esta debería ser la respuesta aceptada, más legible y no destructiva (frente a turno) – user1075613

5
q=${@:0:1};[ ${2} ] && set ${@:2} || set ""; echo $q 

EDITAR

> q=${@:1} 
# gives the first element of the special parameter array ${@}; but ${@} is unusual in that it contains (? file name or something) and you must use an offset of 1; 

> [ ${2} ] 
# checks that ${2} exists ; again ${@} offset by 1 
    > && 
    # are elements left in  ${@} 
     > set ${@:2} 
     # sets parameter value to ${@} offset by 1 
    > || 
    #or are not elements left in ${@} 
     > set ""; 
     # sets parameter value to nothing 

> echo $q 
# contains the popped element 

Un ejemplo de pop con arreglo regular

LIST=(one two three) 
    ELEMENT=(${LIST[@]:0:1});LIST=("${LIST[@]:1}") 
    echo $ELEMENT 
+0

También explique el código para ser más educativo. – lpapp

+0

@LaszloPapp, verdadero – Prospero

+0

'q = $ {@: 0: 1}' (por cierto, tu explicación lo cita erróneamente como 'q = $ {@: 1}') debe ser 'q = $ {@: 1: 1} 'para ser más claro:' $ @ 'comienza con el índice * 1 *, presumiblemente para hacer paralelo a los parámetros explícitos' $ 1', '$ 2', ... - el elemento 0 tiene _no_valor (a diferencia de su homólogo explícito,' $ 0', que refleja el archivo shell/script). '[$ {2}]' will _break_ should '$ 2' contendrá espacios integrados; no tendrás ese problema si usas '[[$ {2}]]' en su lugar. Dicho esto, el condicional y la rama '||' no son necesarios: si solo hay 1 argumento, '$ {@: 2}' simplemente se expandirá a la cadena vacía (cont.). – mklement0