2012-07-25 15 views
21

Quiero recorrer una lista de ruta que he obtenido de un comando echo $VARIABLE.Looping a través de los elementos de una variable de ruta en Bash

Por ejemplo:

echo $MANPATH volverá

/usr/lib:/usr/sfw/lib:/usr/info

Así que es tres caminos diferentes, cada uno separado por dos puntos. Quiero hacer un bucle en cada uno de esos caminos. ¿Hay una manera de hacer eso? Gracias.

Gracias por todas las respuestas hasta el momento, parece que en realidad no necesito un bucle después de todo. Solo necesito una forma de sacar el colon para poder ejecutar un comando ls en esas tres rutas.

Respuesta

15

Puede usar la sustitución de patrón de Bash parameter expansion para llenar su variable de bucle. Por ejemplo:

MANPATH=/usr/lib:/usr/sfw/lib:/usr/info 

# Replace colons with spaces to create list. 
for path in ${MANPATH//:/ }; do 
    echo "$path" 
done 

Nota: No adjunte la expansión de sustitución entre comillas. Desea que los valores expandidos de MANPATH sean interpretados por for-loop como palabras separadas, en lugar de como una sola cadena.

+5

¿Y qué pasa si contienen espacios? –

+7

Según tengo entendido, esto no funciona cuando cualquiera de las subcadenas contiene espacios, que es exactamente por lo que $ PATH usa un separador que no es de espacio. La respuesta de @ choroba a continuación es correcta en este sentido. – intelfx

+1

@intelfx: la pregunta está etiquetada [tag: linux]. Si tiene espacios en su * MANPATH * en Linux, entonces está haciendo mal Linux. Q.E.D. –

0

Puede utilizar Bash para X en $ {} la notación de lograr esto:

for p in ${PATH//:/$'\n'} ; do 
    echo $p; 
done 
+3

Esto no maneja espacios. – codeforester

39

Puede configurar el separador de campo interno:

(IFS=: 
    for p in $MANPATH; do 
     echo "$p" 
    done 
) 

he usado un subnivel por lo que el cambio de IFS no se refleja en mi caparazón actual.

+6

Creo que este es el que funciona incluso si $ MANPATH contiene espacios en blanco. – user1277476

+3

¡Sí! Esta es la única respuesta que funciona de manera consistente con las rutas que contienen espacios en blanco (o lo que sea que el IFS esté en su sistema). Probado en Cygwin, Fedora, Ubuntu, y trabajado para mí en $ PATH – hobs

+1

Maneja bien los espacios, pero no maneja los caracteres glob. – codeforester

0
for p in $(echo $MANPATH | tr ":" " ") ;do 
    echo $p 
done 
+1

-1 para las interpolaciones variables no citadas, el 'eco' indeseable y el subproceso cuando la sustitución puede ser realizada por el shell. – tripleee

+2

Necesita comillas, pero también es mucho más legible que el ruido de línea integrado en el shell. Las subcapas no son el enemigo. – user1277476

+0

Esto no se puede arreglar (simplemente) agregando comillas, y tiene al menos otro problema que @tripleee no mencionó. Ver [¿Por qué printf es mejor que echo?] (Https://unix.stackexchange.com/q/65803). Sin embargo, la puntuación muy baja actual parece dura dado que funcionalmente no es mucho peor que la "solución" aceptada. – pjh

9

La forma canónica de ello, en Bash, es utilizar el read incorporado adecuadamente:

IFS=: read -r -d '' -a path_array < <(printf '%s:\0' "$MANPATH") 

Ésta es la única solución robusta: va a hacer exactamente lo que quiere: dividir la cadena de el delimitador : y sea seguro con respecto a espacios, saltos de línea y caracteres globales como *, [ ], etc. (a diferencia de las otras respuestas: están todos rotos).

Después de este comando, tendrá una serie path_array, y puede recorrer en él:

for p in "${path_array[@]}"; do 
    printf '%s\n' "$p" 
done 
2

De esta manera se puede ir con seguridad a través de la $PATH con un solo bucle, mientras que seguirá siendo el $IFS lo mismo dentro o fuera del bucle.

while IFS=: read -d: -r path; do # `$IFS` is only set for the `read` command 
    echo $path 
done <<< "${PATH:+"${PATH}:"}" # append an extra ':' if `$PATH` is set 

Puede comprobar el valor de $IFS,

IFS='xxxxxxxx' 
while IFS=: read -d: -r path; do 
    echo "${IFS}${path}" 
done <<< "${PATH:+"${PATH}:"}" 

y la salida será algo como esto.

xxxxxxxx/usr/local/bin 
xxxxxxxx/usr/bin 
xxxxxxxx/bin 

Referencia al another question on StackExchange.

0
IFS=: 
arr=(${MANPATH}) 
for path in "${arr[@]}" ; do # <- quotes required 
    echo $path 
done 

... sí tener cuidado de espacios: o) pero también añade elementos vacíos si tiene algo como:

:/usr/bin::/usr/lib: 

... entonces índice de 0,2 habrá vacía (' '), no se puede decir por qué índice de 4 isnt fija en todo

+0

Esto no maneja los caracteres glob. – pjh

0

Esto también puede ser resuelto con Python, en la línea de comandos:

python -c "import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]" echo {} 

o como una alias:

alias foreachpath="python -c \"import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]\"" 

Con Ejemplo de uso:

foreachpath echo {} 

La ventaja de este enfoque es que {} será reemplazado por cada trayectoria en sucesión. Esto se puede usar para construir todo tipo de comandos, por ejemplo, para listar el tamaño de todos los archivos y directorios en los directorios en $PATH. incluyendo directorios con espacios en el nombre:

foreachpath 'for e in "{}"/*; do du -h "$e"; done' 

Aquí hay un ejemplo que acorta la longitud de la variable $PATH mediante la creación de enlaces simbólicos a todos los archivos y directorios en el $PATH en $HOME/.allbin. Esto no es útil para el uso diario, pero puede ser útil si se recibe el mensaje de error too many arguments en un recipiente docker, porque bitbake utiliza la plena $PATH como parte de la línea de comandos ...

mkdir -p "$HOME/.allbin" 
python -c "import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]" 'for e in "{}"/*; do ln -sf "$e" "$HOME/.allbin/$(basename $e)"; done' 
export PATH="$HOME/.allbin" 

Esto debería también, en teoría, acelera el uso normal de shell y los scripts de shell, ya que hay menos rutas para buscar cada comando que se ejecuta. Se es bastante hacky, sin embargo, por lo que no recomendamos que nadie acortar su $PATH esta manera.

Los foreachpath alias puede ser útil, sin embargo.

Cuestiones relacionadas