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?
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
.
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}"
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.
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.
Voici quelques approches supplémentaires. J'utilise un PATH
avec 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 cut
qui é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 print
name__. 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 Perl
se comporte comme awk
name__: 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 join
name__ing le tableau avec des nouvelles lignes puis une impression.
grep
simple avec magie PCRE:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
-o
permet à grep
d’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 print
name__. Une nouvelle ligne sera donc ajoutée à chaque print
name__.
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!
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
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
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"
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
Ruby -0072 -ne 'puts chomp' <<<$PATH
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
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"'
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
À 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.
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:
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.
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 (RS
name__) 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 gsub
n'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 PATH
ne 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.)
jq -Rr 'gsub(":";"\n")' <<<$PATH
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
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?
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.
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
).
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.