Je n'arrive pas à comprendre comment lister les différents chemins $PATH
séparément afin qu'ils ressemblent à ceci:
/bin
/usr/bin
/usr/local/bin
etc.
Est-ce que quelqu'un sait la bonne variable pour cela?
Je n'arrive pas à comprendre comment lister les différents chemins $PATH
séparément afin qu'ils ressemblent à ceci:
/bin
/usr/bin
/usr/local/bin
etc.
Est-ce que quelqu'un sait la bonne variable pour cela?
Réponses:
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 :
avec de nouvelles lignes \n
.
python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
python -c "print r'$PATH'.replace(':', '\n')"
(utilisation d'une chaîne brute en cas de barres obliques inverses)
tr
travaillé pour moi (sur mac, d'ailleurs). Merci.
.bash_profile
, ajoutez la comme suit:alias path='tr ":" "\n" <<< "$PATH"'
Utilisez les paramètres de bash :
echo "${PATH//:/$'\n'}"
Cette opération remplace toutes :
dans $PATH
par un saut de ligne ( \n
) et imprime 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}"
${parameter/pattern/string}
Utiliser IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
contient les caractères sur lesquels bash scinde, donc un IFS
avec :
make fait scinder le développement de $PATH
on :
. printf
boucle les arguments sur la chaîne de format jusqu'à ce qu'ils soient épuisés. Nous devons désactiver la fonction Globbing (extension de caractères génériques) set -f
afin que les caractères génériques dans les noms de répertoires PATH ne soient pas développés.
Utilisant 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.
echo $PATH | xargs -n1 -d: echo
redondante ou peu importe?
echo $PATH | xargs -n1 -d:
fera la même chose pour vous, mais vous utiliserez un shell supplémentaire. Le premier évaluera echo $PATH
et dirigera la sortie vers le prochain shell pour faire le reste.
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
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 cut
celui qui échoue sur 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
Cela -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 tout remplacer :
par des nouvelles lignes.
$ perl -lne 'print for split /:/' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Le -l
ajoute une nouvelle ligne à chaque print
appel. Ici, le script scinde son entrée :
, puis boucle sur chaque élément scindé et l’imprime.
$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Les -a
marques perl
se comportent comme ceci awk
: il divisera chacune de ses lignes en entrée sur le caractère donné par -F
(donc :
, ici) et sauvegardera le résultat dans le tableau @F
. Le $"
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. Donc, le définir sur une nouvelle ligne fera print @list
imprimer 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 de l’utiliser $"
, nous allons explicitement join
insérer le tableau avec des nouvelles lignes, puis l’imprimer.
Simple grep
avec la magie PCRE:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Le -o
fait d' grep
imprimer uniquement la partie correspondante de chaque ligne, de sorte que chaque correspondance est imprimée sur une ligne distincte. Le -P
permet PCRE (PCRE). La regex recherche des segments de non :
( [^:]+
) qui suivent le début de la ligne ( ^
) ou un :
caractère. Il \K
s’agit d’une astuce PCRE qui signifie "jeter tout élément correspondant avant ce point" et qui est utilisée ici pour éviter d’imprimer :
aussi.
Et une cut
solution (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 permettent de -d:
définir le délimiteur d'entrée sur :
, -f 1-
ce qui signifie d'imprimer tous les champs (du premier au dernier) et de --output-delimiter=$'\n'
définir le délimiteur de sortie. Le $'\n'
est cité ANSI C et est un moyen d'imprimer un caractère de nouvelle ligne dans la coquille.
Dans tous les exemples ci-dessus, j'utilise l' opérateur string ( <<<
) de bash (et de certains autres shells ) 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 dans les commentaires qu'il est trop bon de ne pas inclure:
$ perl -0x3a -l012 -pe '' <<<"$PATH"
C'est ce qu'on appelle le golf . Le -0
spécifie le séparateur d'enregistrement d'entrée en tant que 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 mettons cela à un :
qui est x3a
en hexadécimal (essayez printf '\x3a\n'
). Le -l
fait trois choses. Tout d'abord, il supprime le séparateur d'enregistrement d'entrée ( $/
) à la fin de chaque ligne (ce qui supprime effectivement le :
here), 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
is \n
). Si $\
est défini, il est ajouté à la fin de chaque print
appel, ainsi une nouvelle ligne sera ajoutée à chacun print
.
La -pe
volonté p Rint chaque ligne d'entrée après l' application du 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!
perl -0x3a -l012 -pe '' <<<$PATH
. Explanation: -0
définit le séparateur d'enregistrement d'entrée (spécifié en notation hexadécimale / octale, x3A est un signe deux-points), -l
effectue deux opérations: 1) il décompose le séparateur d'enregistrement d'entrée, 2) il définit le séparateur d'enregistrement de sortie s'il en existe un (en notation octale , 012 est une nouvelle ligne). Une -p
boucle imprime la valeur de $ _, qui sera chaque ligne lue.
-F
info. Je l'utilise en -F
association avec -an
des années, je n'ai jamais réalisé que l'un impliquait les autres. A propos, j’ai vu Serg parler de Code Golf , mais je pense que vous apprécieriez également Unix et Linux si vous aimez ce genre de chose.
-l
ajoute également le séparateur d'enregistrement de sortie donné à la fin de chaque appel d'impression. En fait, print ajoute toujours le séparateur d'enregistrement de sortie,, $/
à la fin d'une chaîne - si le séparateur d'enregistrement de sortie est défini. Par défaut, c'est undef. Donc, le jeu est -l
défini $/
, ce qui oblige print à ajouter la nouvelle ligne à la fin de la chaîne.
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"'
Comme 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 une get_env()
fonction (voir la 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 la version alternative de Python via des 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 jamais vous vous retrouviez à l'utiliser, la solution dans Ruby serait la suivante:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
Comme suggéré par 7stud (Merci beaucoup!) Dans les commentaires , cela peut aussi être raccourci avec
ruby -F: -ane 'puts $F' <<<$PATH
et de cette façon
ruby -0072 -ne 'puts chomp' <<<$PATH
Nous pouvons utiliser la split()
fonction pour décomposer la ligne lue en tableau, et utiliser la for-each
boucle pour imprimer chaque élément sur une ligne séparée.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
imprime automatiquement les éléments d'un tableau sur des lignes séparées! Vous pouvez également faire en sorte que les commutateurs fassent le fractionnement: ruby -F: -ane 'puts $F' <<<$PATH
Explication: -F
définit $;
le caractère spécifié, qui est le séparateur par défaut utilisé par String :: split ($; a une valeur par défaut de nil, qui sépare les espaces). -a
appelle $ _. split, où $ _ est une ligne lue à l'aide de gets ()) et assigne le tableau résultant $F
.
-F
drapeau - je viens juste de commencer avec Ruby, donc je fais les choses de façon légèrement rudimentaire.
ruby -0072 -ne 'puts chomp' <<<$PATH
. Explanation: -0
définit le séparateur d'enregistrement d'entrée (spécifiez un caractère au format octal; 072 est un signe deux-points). Ruby emploie $ _ de manière similaire à Perl. La méthode gets () (utilisée dans la -n
boucle) définit $ _ sur la ligne en cours de lecture. Et chomp()
sans argument, chomps $ _. J'aime toujours mieux le tien. :)
-F
flag, est plus court. Si vous faites echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
cela, cela me dit que c'est 271 octets, mais celui avec un nombre octal est 276. C'est pour la commande entière, bien sûr, si nous considérons que seul le code lui puts $F
- même est nettement plus court. :) Au fait, connaissez-vous Code Golf ? C'est le site pour les solutions de programmation de puzzles dans le plus petit nombre d'octets. Il y a une question liée à celle-ci: codegolf.stackexchange.com/q/96334/55572
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 en utilisant:
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
python3 -c "import os; [print(p) for p in os.getenv('PATH').split(':')]"
À 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.
echo $PATH | awk '{gsub(/\:/,"\n");print}'
fileinput
pouvoir utiliser input
:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
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
Ensuite, listpath -p dirs
produit une liste.
Explication de la réponse @Cyrus
echo "${PATH//:/$'\n'}"
Remarques:
Citation ANSI-C - cela explique $ 'some \ ntext'
Shell Parameter Expansion - explique $ {paramètre / modèle / chaîne}. Si le modèle commence par '/', toutes les correspondances de modèle sont remplacées par une chaîne.
Nous avons donc:
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 l’ print $0
implicite (c’est l’action par défaut, elle 1
vaut true, elle est exécutée 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
) sur :
avant de lire l’entrée, AWK analyse automatiquement un séparateur deux-points $PATH
dans ses noms de répertoire constitutent. AWK s'étend $0
à chaque enregistrement entier, la nouvelle ligne reste le séparateur d'enregistrement de sortie et aucune boucle gsub
n'est nécessaire.
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, à moins que AWK reconstruise l’enregistrement (voir ci-dessous), il n’ya aucun problème à avoir des espaces ou des tabulations (les séparateurs de champs par défaut) dans l’entrée. Votre PATH
probablement ne contient pas d'espaces sur un système Ubuntu, mais si c'est le cas, cela fonctionnera toujours.
Il convient de noter, en guise de remarque, que la capacité d'AWK d'interpréter un enregistrement en tant que collection de champs devient utile pour le problème connexe de la construction d'une table de composants de répertoire :
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 $1=$1
tâche curieuse sert à forcer AWK à 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
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, il suffit de lui envoyer un message d’écho PATH
pour qu’elle traduise ( tr
) afin de 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 préoccupés?
Si vous souhaitez une solution relativement permanente dans votre .bashrc
utilisation interactive, vous pouvez aliaser la commande suivante 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 des 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 vous contentez de pirater la ligne de commande, si vous ne l'avez pas encore aliasée.
Alternativement, 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'à son épuisement:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
Cette méthode de création de fonctions , IFS
et printf
sont fournis par posix, donc il devrait fonctionner dans la plupart posix comme des coquilles ( en particulier Dash, qui Ubuntu généralement alias comme 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 seulement Python 3 (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.
Cette solution est plus simple que les solutions Java , C , go and 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