Boucle à travers les éléments d'une variable path en Bash

je veux faire une boucle à travers une liste de chemins que j'ai obtenue à partir d'une commande echo $VARIABLE .

par exemple:

echo $MANPATH sera de retour

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

donc c'est trois chemins différents, chacun séparé par un côlon. Je veux boucle si chacune de ces chemins. Est-il un moyen de le faire? Grâce.

Merci pour toutes les réponses jusqu'à présent, il semble que je n'ai pas besoin une boucle après tout. J'ai juste besoin d'un moyen d'enlever le colon Pour pouvoir exécuter une commande ls sur ces trois chemins.

24
demandé sur codeforester 2012-07-25 21:59:39
la source

8 ответов

vous pouvez utiliser la substitution de patron de Bash expansion de paramètre pour peupler votre variable de boucle. Par exemple:

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

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

Note: Ne pas inclure l'extension de substitution dans les guillemets. Vous voulez que les valeurs étendues de MANPATH soient interprétées par la boucle for comme des mots séparés, plutôt que comme une chaîne simple.

15
répondu Todd A. Jacobs 2012-07-25 23:40:37
la source

vous pouvez définir le séparateur de champ interne:

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

j'ai utilisé un subshell de sorte que le changement de IFS ne se reflète pas dans mon shell actuel.

43
répondu choroba 2015-04-29 19:35:11
la source

la façon canonique de le faire, à Bash, est d'utiliser le read construire de manière appropriée:

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

C'est la seule solution robuste: fera exactement ce que vous voulez: diviser la chaîne sur le délimiteur : et être sûr en ce qui concerne les espaces, les lignes et les caractères globulaires comme * , [ ] , etc. (contrairement aux autres réponses: elles sont toutes cassées).

Après cette commande, vous aurez un tableau path_array , et vous pouvez boucle sur elle:

for p in "${path_array[@]}"; do
    printf '%s\n' "$p"
done
12
répondu gniourf_gniourf 2015-04-29 19:43:39
la source

de cette façon, vous pouvez passer en toute sécurité le $PATH avec une seule boucle, tandis que $IFS restera le même à l'intérieur ou à l'extérieur de la boucle.

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

vous pouvez vérifier la valeur de $IFS ,

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

et la sortie sera quelque chose comme cela.

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

référence à une autre question sur StackExchange .

3
répondu Yi H. 2017-04-13 15:36:24
la source

cela peut aussi être résolu avec Python, sur la ligne de commande:

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

ou comme alias:

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

Avec exemple d'usage:

foreachpath echo {}

l'avantage de cette approche est que {} sera remplacé par chaque chemin consécutif. Cela peut être utilisé pour construire toutes sortes de commandes, par exemple pour lister la taille de tous les fichiers et répertoires dans les répertoires de $PATH . comprendre répertoires avec des espaces dans le nom:

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

voici un exemple qui raccourcit la longueur de la variable $PATH en créant des liens symboliques vers chaque fichier et répertoire dans $PATH dans $HOME/.allbin . Ce n'est pas utile pour l'usage quotidien, mais peut peut être utile si vous obtenez le too many arguments message d'erreur dans un docker conteneur, parce que bitbake utilise le plein $PATH comme partie de la ligne de commande...

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"

cela devrait aussi, en théorie, accélérer l'utilisation régulière du shell et les scripts shell, puisqu'il y a moins de chemins pour rechercher chaque commande exécutée. est assez hacky, cependant, de sorte que je ne recommande pas que n'importe qui raccourcir $PATH de cette façon.

l'alias foreachpath pourrait être utile, cependant.

1
répondu Alexander 2018-03-08 13:43:02
la source

vous pouvez utiliser Bash's pour X en ${} notation pour accomplir ceci:

for p in ${PATH//:/$'\n'} ; do
    echo $p;
done
0
répondu Hunter McMillen 2012-07-25 22:04:57
la source
for p in $(echo $MANPATH | tr ":" " ") ;do
    echo $p
done
0
répondu rayd09 2012-07-25 22:09:34
la source
IFS=:
arr=(${MANPATH})
for path in "${arr[@]}" ; do # <- quotes required
   echo $path
done

... il prend soin des espaces :o), mais ajoute également des éléments vides si vous avez quelque chose comme:

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

... alors l'index 0,2 sera vide ( " ), ne peut pas dire pourquoi l'index 4 n'est pas réglé du tout

0
répondu Acid 2015-09-11 05:29:27
la source

Autres questions sur