web-dev-qa-db-fra.com

Comment afficher les chemins dans $ PATH séparément

Je n'arrive pas à comprendre comment lister les différents chemins dans $PATH de manière à ce qu'ils ressemblent à ceci:

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

etc.

Est-ce que quelqu'un sait la bonne variable pour cela?

42
HankG

Essayez sed:

$ sed 's/:/\n/g' <<< "$PATH"

Ou tr:

$ tr ':' '\n' <<< "$PATH"

Ou python:

$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"

Ici, tout ce qui précède remplacera toutes les occurrences de : par les nouvelles lignes \n.

55
heemayl

Utilisez bash expansion des paramètres :

echo "${PATH//:/$'\n'}"

Ceci remplace tout : dans $PATH par une nouvelle ligne (\n) et affiche le résultat. Le contenu de $PATH reste inchangé.
Si vous souhaitez uniquement remplacer le premier :, supprimez la deuxième barre oblique: echo -e "${PATH/:/\n}"

61
Cyrus

Utiliser IFS:

(set -f; IFS=:; printf "%s\n" $PATH)

IFS contient les caractères sur lesquels bash divise, donc un IFS avec : permet à bash de décomposer le développement de $PATH sur :. printf boucle les arguments sur la chaîne de format jusqu'à ce qu'ils soient épuisés. Nous devons désactiver le globbing (développement de caractères génériques) à l'aide de set -f afin que les caractères génériques dans les noms de répertoires PATH ne soient pas développés.

26
muru

Utilisation de xargs:

xargs -n1 -d: <<< $PATH

De man xargs

-n max-args
          Use  at  most  max-args  arguments per command line.

 -d delim
          Input  items  are terminated by the specified character.
14
souravc

Voici quelques approches supplémentaires. J'utilise un PATHavec des répertoires contenant des barres obliques inverses, des espaces et même une nouvelle ligne pour montrer qu'ils doivent fonctionner avec n'importe quoi (sauf le cutqui échoue dans les nouvelles lignes):

$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even 
new lines
  • Quelques manières de Perl:

    $ Perl -pe 's/:/\n/g' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    -p signifie "imprimer chaque ligne d'entrée après l'application du script donné par -e". Le script utilise l'opérateur de substitution (s/oldnew/) pour remplacer tous les : par des nouvelles lignes.

    $ Perl -lne 'print for split /:/' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    -l ajoute une nouvelle ligne à chaque appel printname__. Ici, le script divise son entrée sur :, puis boucle sur chaque élément divisé et l’imprime.

    $ Perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    Le -a fait que Perlse comporte comme awkname__: il divisera chacune de ses lignes d'entrée sur le caractère donné par -F (donc :, ici) et sauvegardera le résultat dans le tableau @F. $" est une variable Perl spéciale, le "séparateur de liste", dont la valeur est imprimée entre chaque élément d'une liste imprimée. Ainsi, si vous le définissez sur une nouvelle ligne, print @list imprimera chaque élément de @list, puis une nouvelle ligne. Ici, nous l’utilisons pour imprimer @F.

    $ Perl -F: -ane 'print join "\n", @F' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    Même idée que ci-dessus, un peu moins golfée. Au lieu d'utiliser $", nous sommes explicitement joinname__ing le tableau avec des nouvelles lignes puis une impression.

  • grepsimple avec magie PCRE:

    $ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    -o permet à grepd’imprimer uniquement la partie correspondante de chaque ligne, de sorte que chaque correspondance est imprimée sur une ligne distincte. -P active les expressions régulières compatibles Perl (PCRE). La regex recherche des étendues non -: ([^:]+) qui suivent le début de la ligne (^) ou un caractère :. Le \K est une astuce PCRE qui signifie "jeter tout ce qui correspond avant ce point" et est utilisé ici pour éviter d’imprimer le : également.

  • Et une solution cut(celle-ci échoue sur les nouvelles lignes, mais peut traiter les barres obliques inverses et les espaces):

    $ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    Les options utilisées sont -d:, qui définit le délimiteur d'entrée sur :, -f 1-, ce qui signifie que tous les champs doivent être imprimés (du premier au dernier) et --output-delimiter=$'\n', qui définit le délimiteur de sortie. $'\n' est citation ANSI C et permet d'imprimer un caractère de nouvelle ligne dans le shell.

Dans tous les exemples ci-dessus, j'utilise l'opérateur de bash (et d'autres shells) ici chaîne (<<<) pour transmettre une chaîne en tant qu'entrée à un programme. Donc, command <<<"foo" est équivalent à echo -n "foo" | command. Notez que je cite toujours "$PATH", sans les guillemets, le shell aurait mangé le caractère de nouvelle ligne.


@ 7stud a donné une autre approche à les commentaires c'est trop beau pour ne pas inclure:

$ Perl -0x3a -l012 -pe '' <<<"$PATH"

C'est ce qu'on appelle golf . -0 spécifie le séparateur d'enregistrement d'entrée sous forme de nombre octal ou hexadécimal. C'est ce qui définit une "ligne" et sa valeur par défaut est \n, un caractère de nouvelle ligne. Ici, nous le configurons avec un : qui est x3a au format hexadécimal (essayez printf '\x3a\n'). Le -l fait trois choses. Premièrement, il supprime le séparateur d'enregistrement d'entrée ($/) de la fin de chaque ligne (en supprimant effectivement le : ici), et deuxièmement, il définit le séparateur d'enregistrement de sortie ($\) sur la valeur octale ou hexadécimale qui lui est donnée (012 est \n). Si $\ est défini, il est ajouté à la fin de chaque appel printname__. Une nouvelle ligne sera donc ajoutée à chaque printname__.

Le -pe va p imprimer chaque ligne d’entrée après avoir appliqué le script donné par -e. Ici, il n'y a pas de script car tout le travail est effectué avec l'option flags comme décrit ci-dessus!

7
terdon

Voici l'équivalent en Go:

$ cat path.go
package main

import (
    "fmt"
    "os"
    "strings"
)

func main() {
    for _, p := range strings.Split(os.Getenv("PATH"), ":") {
        fmt.Println(p)
    }
}

$ go run path.go
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin
/home/nathan/.local/bin
/home/nathan/go/bin
7
Nathan Osman

Dans cette réponse:

  1. C
  2. Python
  3. Ruby
  4. Awk alternative

1. C

Puisque tous les langages de script ont déjà été utilisés, je vais utiliser C. Il est assez facile d’obtenir des variables d’environnement avec la fonction get_env() (voir documentation de la bibliothèque GNU C ). Le reste est simplement une manipulation de personnage

bash-4.3$ cat get_path.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char *path = getenv("PATH");
    int length = strlen(path) -1;
    for(int i=0;i<=length;i++){
        if (path[i] == ':')
            path[i] = '\n';
        printf("%c",path[i]);
    }
    printf("\n");
    return 0;
}
bash-4.3$ gcc get_path.c
bash-4.3$ ./a.out 
/home/xieerqi/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin
/opt/microchip/xc16/v1.25/bin
/opt/microchip/xc32/v1.40/bin
/opt/microchip/xc8/v1.35/bin
/home/xieerqi/bin
/home/xieerqi/bin/sh

2. Python

Mais aussi parce que "pourquoi pas", voici l'alternative python version via les arguments en ligne de commande sys.argv

python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"

3. rubis

Ruby ne vient pas avec Ubuntu par défaut, contrairement au compilateur C et à l'interpréteur Python, mais si vous vous trouvez un jour à l'utiliser, la solution dans Ruby serait la suivante:

Ruby -ne 'puts $_.split(":")' <<< "$PATH"

Comme suggéré par 7stud (Merci beaucoup!) Dans le commentaires , cela peut aussi être raccourci avec

Ruby -F: -ane 'puts $F' <<<$PATH

et de cette façon

Ruby -0072 -ne 'puts chomp' <<<$PATH

4. Alternative awk

Nous pouvons utiliser la fonction split() pour décomposer la ligne lue dans un tableau et utiliser la boucle for-each pour imprimer chaque élément sur une ligne distincte.

awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
6

La seule façon de ne pas avoir été mentionnée est la façon dont je l'utilise depuis des années:

echo $PATH | tr ":" "\n"

alors, dans votre .profile ou .bash_profile ou autre, vous pouvez ajouter:

alias path='echo $PATH | tr ":" "\n"'

5
dolt

Nous avons besoin de plus de Java!

public class GetPathByLine {
    public static void main(String[] args) {
        for (String p : System.getenv("PATH").split(":")) {
            System.out.println(p);
        }
    }
}

Enregistrez ceci dans GetPathByLine.Java et compilez-le avec:

javac GetPathByLine.Java

Courir avec:

Java GetPathByLine

┌─[17:06:55]─[kazwolfe@BlackHawk]
└──> ~ $ cat GetPathByLine.Java 
public class GetPathByLine {
    public static void main(String[] args) {
        for (String p : System.getenv("PATH").split(":")) {
            System.out.println(p);
        }
    }
}
┌─[17:06:58]─[kazwolfe@BlackHawk]
└──> ~ $ javac GetPathByLine.Java 
┌─[17:07:02]─[kazwolfe@BlackHawk]
└──> ~ $ Java GetPathByLine 
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin
4
Kaz Wolfe

À travers awk.

echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'

À travers le python.

$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
    for i in line.split(":"):
        print(i)'

Notez que l'indentation est très important en python.

3
Avinash Raj

Explication de la réponse @Cyrus

echo "${PATH//:/$'\n'}"

Remarques:

citation ANSI-C - il explique $ 'some\ntext'

Expansion des paramètres du shell - il explique $ {paramètre/modèle/chaîne}, si modèle commence par ‘/’, toutes les correspondances de modèle sont remplacées par chaîne.

Donc nous avons:

  1. un motif /: commençant par '/' pour remplacer toutes les correspondances
  2. une chaîne $ '\ n' qui est citée avec la contraction $ 'anytext' pour traiter le nouveau symbole de ligne (\ n).
2
victorq10

J'utilise les "Bash Path Functions" de Stephen Collyer (voir son article dans Linux Journal ). Cela me permet d’utiliser la "liste séparée par des deux-points" comme type de données dans la programmation Shell. Par exemple, je peux produire une liste de tous les répertoires du répertoire actuel en:

dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done  

listpath -p dirs produit ensuite une liste.

2
waltinator

Une autre méthode AWK consiste à traiter chaque répertoire comme un enregistrement séparé plutôt que comme un champ séparé .

awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"

Je trouve cette syntaxe particulièrement intuitive. Mais, si vous le souhaitez, vous pouvez le raccourcir en rendant implicite le print $0 (il s’agit de l’action par défaut, et 1 a la valeur true, ce qui le fera pour chaque ligne):

awk 'BEGIN{RS=":"} 1' <<<"$PATH"

Le séparateur d'enregistrement par défaut d'entrée et de sortie d'AWK est la nouvelle ligne (saut de ligne). En définissant le séparateur d'enregistrement d'entrée (RSname__) sur : avant de lire l'entrée, AWK analyse automatiquement un $PATH délimité par des deux-points dans ses noms de répertoire constitutent. AWK étend $0 à chaque enregistrement entier, la nouvelle ligne reste le séparateur d'enregistrement en sortie et aucun bouclage ni gsubn'est requis.

ek@Io:~$ echo "$PATH"
/home/ek/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
/home/ek/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin

AWK est souvent utilisé pour analyser des enregistrements dans des champs distincts, mais il n'est pas nécessaire de créer une liste de noms de répertoires.

Cela fonctionne même pour les entrées contenant des espaces (espaces et tabulations), voire plusieurs espaces consécutifs:

ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de    fg:h'
ab               c
de    fg
h

Autrement dit, sauf si AWK doit reconstruire l'enregistrement (voir ci-dessous), il n'y a aucun problème à avoir des espaces ou des tabulations (les séparateurs de champs par défaut) dans le répertoire. contribution. Votre PATHne contient probablement pas d'espaces sur un système Ubuntu, mais s'il le fait, cela fonctionnera toujours.


Il est à noter que la capacité d'AWK à interpréter un enregistrement comme une collection de champs devient utile pour le problème connexe de la construction d'un tableau de répertoire composants :

ek@Io:~$ awk -F/ 'BEGIN{RS=":"; OFS="\t"} {$1=$1; print $0}' <<<"$PATH"
        home    ek      bin
        usr     local   sbin
        usr     local   bin
        usr     sbin
        usr     bin
        sbin
        bin
        usr     games
        usr     local   games
        snap    bin

La curieuse assignation $1=$1 sert à forcer AWK pour reconstruire l'enregistrement .

(Ceci est probablement plus utile dans les cas où un traitement supplémentaire doit être effectué sur les composants, plutôt que dans l'exemple exact de la simple impression du tableau.)

1
Eliah Kagan
jq -Rr 'gsub(":";"\n")' <<<$PATH
1
David Fetter

Cette solution est plus simple que les solutions Java, C, go et awk:

$ LPATH=$PATH wine cmd /c echo %LPATH::=$'\n'% 2> /dev/null
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin

Voici une autre grande possibilité:

$ jrunscript -classpath /usr/share/Java/bsh.jar -e 'print(Java.lang.System.getenv("PATH").replaceAll(":","\n"))'
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin

Cela nécessiterait l'installation de certaines dépendances:

Sudo apt-get install openjdk-8-jdk-headless bsh
0
Gungwald

Comment afficher les chemins dans $ PATH séparément

Ce sont mes méthodes préférées pour ce faire, en fonction de mes cas d'utilisation respectifs et de mes préoccupations concernant la compatibilité et l'utilisation des ressources.

tr

Tout d’abord, si vous avez besoin d’une solution rapide, facile à mémoriser et lisible, rappelez simplement PATH et dirigez-la vers traduction (tr) pour transformer les deux points en nouvelles lignes:

echo $PATH | tr : "\n"

Il y a l'inconvénient d'utiliser deux processus en raison de la canalisation, mais si nous ne faisons que pirater un terminal, en sommes-nous vraiment concernés?

Expansion des paramètres du shell de Bash

Si vous souhaitez une solution relativement permanente dans votre .bashrc pour une utilisation interactive, vous pouvez aliaser la commande suivante en path, mais la lisibilité de cette solution est discutable:

alias path="echo \"${PATH//:/$'\n'}\""

Si motif commence par ‘/’, toutes les correspondances de motif sont remplacées par une chaîne. Normalement, seul le premier match est remplacé.

La commande ci-dessus remplace les deux points par des nouvelles lignes à l'aide de l'extension de paramètres de shell de Bash :

${parameter/pattern/string}

Pour l'expliquer:

          # v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
          #  ^^ ^^^^^----string, $ required to get newline character.
          #   \----------pattern, / required to substitute for *every* :.

Bonne chance de vous en souvenir lorsque vous piratez simplement la ligne de commande, si vous ne l'avez pas encore aliasée.

IFS, testé en bash et dash

Sinon, une approche relativement compatible, lisible et compréhensible qui ne repose pas sur autre chose que le shell utilise la fonction suivante (je suggère dans votre .bashrc.)

La fonction suivante transforme temporairement le séparateur de champs interne (ou d'entrée) en deux points, et lorsqu'un tableau est attribué à printf, il s'exécute jusqu'à ce que le tableau soit utilisé:

path () {
    local IFS=:
    printf "%s\n" ${PATH}
    }

Cette méthode de création de fonction , IFS , et printf sont fournis par posix, il devrait donc fonctionner dans la plupart des shells de type posix (en particulier Dash, qu' Ubuntu alias habituellement sh).

Python

Devez-vous utiliser Python pour cela? Vous pourriez. C’est la commande Python la plus courte à laquelle je puisse penser:

python -c "print('\n'.join('${PATH}'.split(':')))"

ou Python 3 uniquement (et peut-être plus lisible?):

python3 -c "print(*'${PATH}'.split(':'), sep='\n')"

Celles-ci devraient également fonctionner dans n’importe quel environnement Shell habituel, tant que vous avez Python.

0
Aaron Hall