No puedo entender cómo enumerar las diferentes rutas por $PATH
separado para que se vean así:
/bin
/usr/bin
/usr/local/bin
etc.
¿Alguien sabe la variable correcta para esto?
No puedo entender cómo enumerar las diferentes rutas por $PATH
separado para que se vean así:
/bin
/usr/bin
/usr/local/bin
etc.
¿Alguien sabe la variable correcta para esto?
Respuestas:
Prueba sed
:
$ sed 's/:/\n/g' <<< "$PATH"
O tr
:
$ tr ':' '\n' <<< "$PATH"
O python
:
$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"
Aquí todo lo anterior sustituirá todas las ocurrencias de :
con nuevas líneas \n
.
python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
python -c "print r'$PATH'.replace(':', '\n')"
(usando una cadena cruda en caso de barras invertidas)
tr
funcionó para mí (en mac, por cierto). Gracias.
.bash_profile
, agréguelo así:alias path='tr ":" "\n" <<< "$PATH"'
Utilice la expansión de parámetros de bash :
echo "${PATH//:/$'\n'}"
Todo esto sustituye :
en $PATH
por un salto de línea ( \n
) e imprime el resultado. El contenido de $PATH
permanece sin cambios.
Si solo desea reemplazar el primero :
, elimine la segunda barra:echo -e "${PATH/:/\n}"
${parameter/pattern/string}
Usando IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
contiene los caracteres en los que bash se divide, por lo que un IFS
con :
hace que bash divida la expansión de $PATH
on :
. printf
repite los argumentos sobre la cadena de formato hasta que se agoten los argumentos. Necesitamos deshabilitar el uso de globbing (expansión de comodines) set -f
para que los comodines en los nombres de directorio PATH no se expandan.
Utilizando xargs
:
xargs -n1 -d: <<< $PATH
Desde 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
ser redundante o no importa?
echo $PATH | xargs -n1 -d:
hará lo mismo por ti, pero usarás un shell más. El primero evaluará echo $PATH
y canalizará la salida al siguiente shell para hacer el resto.
Aquí está el equivalente 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
Aquí hay algunos enfoques más. Estoy usando un PATH
directorio con barras diagonales, espacios e incluso una nueva línea para mostrar que deberían funcionar con cualquier cosa (excepto la cut
que falla en las nuevas líneas):
$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even
new lines
Algunas formas de Perl:
$ perl -pe 's/:/\n/g' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
El -p
medio "imprime cada línea de entrada después de aplicar la secuencia de comandos dada por -e
". El script está utilizando el operador de sustitución ( s/oldnew/
) para reemplazar todo :
por líneas nuevas.
$ perl -lne 'print for split /:/' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
El -l
agrega una nueva línea a cada print
llamada. Aquí, el script está dividiendo su entrada :
y luego recorre cada elemento dividido y lo imprime.
$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Las -a
marcas se perl
comportan así awk
: dividirá cada una de sus líneas de entrada en el carácter dado por -F
( por lo tanto :
, aquí) y guardará el resultado en la matriz @F
. El $"
es una variable especial de Perl, el "separador de lista", cuyo valor se imprime entre cada elemento de una lista impresa. Por lo tanto, establecerlo en una nueva línea hará que se print @list
imprima cada elemento @list
y luego una nueva línea. Aquí, lo estamos usando para imprimir @F
.
$ perl -F: -ane 'print join "\n", @F' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
La misma idea que la anterior, solo que menos golf. En lugar de usar $"
, estamos explícitamente join
agregando nuevas líneas y luego imprimiendo.
Simple grep
con PCRE magic:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Las -o
marcas grep
imprimir solamente la parte correspondiente de cada línea, por lo que cada partido se imprime en una línea separada. El -P
permite Perl Compatible Regular Expressions (PCRE). La expresión regular busca extensiones de no- :
( [^:]+
) que siguen al principio de la línea ( ^
) o un :
carácter. El \K
es un truco PCRE que significa "descartar cualquier cosa que coincida antes de este punto" y se usa aquí para evitar imprimir :
también.
Y una cut
solución (esta falla en las nuevas líneas, pero puede tratar con barras invertidas y espacios):
$ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Las opciones utilizadas son las -d:
que configuran el delimitador de entrada :
, lo -f 1-
que significa imprimir todos los campos (desde el primero hasta el final) y lo --output-delimiter=$'\n'
que configura el delimitador de salida. El $'\n'
es ANSI C citando y es una manera de imprimir un carácter de nueva línea en la cáscara.
En todos los ejemplos anteriores, estoy usando el operador string ( <<<
) here de bash (y algunos otros shells ) para pasar una cadena como entrada a un programa. Entonces command <<<"foo"
es equivalente a echo -n "foo" | command
. Tenga en cuenta que siempre estoy citando "$PATH"
, sin las comillas, el shell habría comido el carácter de nueva línea.
@ 7stud dio otro enfoque en los comentarios que es demasiado bueno para no incluir:
$ perl -0x3a -l012 -pe '' <<<"$PATH"
Eso es lo que se conoce como golf . El -0
especifica el separador de registro de entrada como un número octal o hexadecimal. Esto es lo que define una "línea" y su valor predeterminado es \n
un carácter de nueva línea. Aquí, lo estamos configurando en un :
que está x3a
en hexadecimal (try printf '\x3a\n'
). El -l
hace tres cosas. Primero, elimina el separador de registro de entrada ( $/
) del final de cada línea, eliminando efectivamente el :
aquí, y segundo, establece el separador de registro de salida ( $\
) a cualquier valor octal o hexadecimal que se le dé ( 012
es \n
). Si $\
se define, se agrega al final de cada print
llamada, por lo que se agregará una nueva línea a cada una print
.
La -pe
voluntad p rint cada línea de entrada después de aplicar la secuencia de comandos dada por -e
. ¡Aquí no hay script porque todo el trabajo se realiza mediante las banderas de opciones como se describe arriba!
perl -0x3a -l012 -pe '' <<<$PATH
. Explicación: -0
establece el separador de registro de entrada (especificado en notación hexadecimal / octal, x3A es un signo de dos puntos), -l
hace dos cosas: 1) divide el separador de registro de entrada, 2) establece el separador de registro de salida si se especifica uno (en notación octal) , 012 es una nueva línea). Un -p
bucle imprime el valor de $ _, que será leído en cada línea .
-F
información. He estado usando -F
combinados -an
durante años, nunca me di cuenta de que uno implicaba a los demás. Por cierto, vi que Serg mencionaba Code Golf , pero creo que también disfrutarías de Unix y Linux si te gusta este tipo de cosas.
-l
también agrega el separador de registro de salida dado al final de cada llamada impresa. De hecho, print siempre agrega el separador de registro de salida,, $/
al final de una cadena, si el separador de registro de salida está definido. Por defecto es undef. Entonces, -l
jus establece $/
, y eso hace que print agregue la nueva línea al final de la cadena.
Probablemente, la única forma en que no se ha mencionado es la forma en que lo he estado usando durante años:
echo $PATH | tr ":" "\n"
entonces, en su .profile o .bash_profile o lo que sea, puede agregar:
alias path='echo $PATH | tr ":" "\n"'
Como ya se han tomado todos los lenguajes de secuencias de comandos, iré con C. Es bastante fácil obtener variables de entorno con get_env()
función (consulte la documentación de la Biblioteca GNU C ). El resto es simplemente manipulación de personajes.
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
Pero también porque "por qué no", aquí hay una versión alternativa de Python a través de argumentos de línea de comando sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
Ruby no viene con Ubuntu por defecto, a diferencia del compilador de C y el intérprete de Python, pero si alguna vez lo usa, la solución en Ruby sería esta:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
Como lo sugirió 7stud (¡Muchas gracias!) En los comentarios , esto también se puede acortar con
ruby -F: -ane 'puts $F' <<<$PATH
y de esta manera
ruby -0072 -ne 'puts chomp' <<<$PATH
Podemos utilizar la split()
función para desglosar la línea leída en una matriz y usar el for-each
bucle para imprimir cada elemento en una línea separada.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
¡Imprime automáticamente los elementos de una matriz en líneas separadas! También puede hacer que los interruptores hagan la división: ruby -F: -ane 'puts $F' <<<$PATH
Explicación: se -F
establece $;
en el carácter especificado, que es el separador predeterminado utilizado por String :: split ($; tiene un valor predeterminado de nil, que se divide en espacios en blanco). -a
llama a $ _. split, donde $ _ es una línea leída usando gets ()) y asigna la matriz resultante a $F
.
-F
bandera, recién estoy comenzando con Ruby, así que estoy haciendo las cosas de una manera un poco tosca.
ruby -0072 -ne 'puts chomp' <<<$PATH
. Explicación: -0
establece el separador de registro de entrada (especifique un carácter en formato octal; 072 es dos puntos). Ruby emplea $ _ de manera similar a Perl. El método gets () (usado en el -n
bucle) establece $ _ en la línea actual que se lee. Y chomp()
sin un argumento, muerde $ _. Todavía me gusta más el tuyo. :)
-F
bandera, es más corto. Si lo hace, echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
me dice que es 271, bytes, pero el número octal es 276. Eso es para todo el comando, por supuesto, si consideramos que solo el código en sí puts $F
es claramente más corto. :) Por cierto, ¿sabes sobre Code Golf ? Es el sitio de soluciones para programar rompecabezas en el menor número de bytes. Hay una pregunta relacionada con esta: codegolf.stackexchange.com/q/96334/55572
¡Necesitamos más Java!
public class GetPathByLine {
public static void main(String[] args) {
for (String p : System.getenv("PATH").split(":")) {
System.out.println(p);
}
}
}
Guarde esto GetPathByLine.java
y compílelo usando:
javac GetPathByLine.java
Corre con:
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(':')]"
A través de awk.
echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'
A través de pitón.
$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
for i in line.split(":"):
print(i)'
Tenga en cuenta que la sangría es muy importante en Python.
echo $PATH | awk '{gsub(/\:/,"\n");print}'
fileinput
cuando uno podía utilizar input
:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
Utilizo las "Funciones de ruta de acceso Bash" de Stephen Collyer (vea su artículo en Linux Journal ). Me permite usar la "lista separada por dos puntos" como un tipo de datos en la programación de shell. Por ejemplo, puedo generar una lista de todos los directorios en el directorio actual:
dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done
Luego, listpath -p dirs
produce una lista.
Explicación para la respuesta @Cyrus
echo "${PATH//:/$'\n'}"
Notas:
Cita ANSI-C : explica $ 'some \ ntext'
Expansión de parámetros de Shell : explica $ {parámetro / patrón / cadena}. Si el patrón comienza con '/', todas las coincidencias del patrón se reemplazan con una cadena.
Entonces tenemos:
Otra forma AWK es tratar cada directorio como un registro separado , en lugar de como un campo separado .
awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
Encuentro esa sintaxis particularmente intuitiva. Pero, si lo desea, puede acortarlo haciendo print $0
implícito (es la acción predeterminada y se 1
evalúa como verdadera, lo que hace que se haga para cada línea):
awk 'BEGIN{RS=":"} 1' <<<"$PATH"
El separador de registro de entrada y salida predeterminado de AWK es la nueva línea (salto de línea). Al configurar el separador de registro de entrada ( RS
) :
antes de leer la entrada, AWK analiza automáticamente un delimitado por dos puntos $PATH
en sus nombres de directorio constitutivos. AWK se expande $0
a cada registro completo, la nueva línea sigue siendo el separador de registros de salida , y no gsub
se necesita hacer un bucle .
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 a menudo se usa para analizar registros en campos separados, pero no hay necesidad de eso solo para construir una lista de nombres de directorio.
Esto funciona incluso para entradas que contienen espacios en blanco (espacios y pestañas), incluso múltiples espacios en blanco consecutivos:
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de fg:h'
ab c
de fg
h
Es decir, a menos que haga que AWK reconstruya el registro (consulte a continuación), no hay problema en tener espacios o pestañas (los separadores de campo predeterminados) en la entrada. Su PATH
probablemente no contiene espacios en un sistema Ubuntu, pero si lo hace, esto todavía va a funcionar.
Vale la pena mencionar, como nota al margen, que la capacidad de AWK de interpretar un registro como una colección de campos se vuelve útil para el problema relacionado de construir una tabla de componentes de directorio :
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 curiosa $1=$1
asignación sirve para forzar a AWK a reconstruir el registro .
(Esto es probablemente más útil para casos en los que se debe realizar un procesamiento adicional en los componentes, que para el ejemplo exacto que se muestra de simplemente imprimir la tabla).
jq -Rr 'gsub(":";"\n")' <<<$PATH
Cómo mostrar las rutas en $ PATH por separado
Estas son mis formas preferidas de hacerlo en función de mis respectivos casos de uso y preocupaciones sobre la compatibilidad y el uso de recursos.
tr
Primero, si necesita una solución rápida, fácil de recordar y legible, simplemente repítala y canalícela PATH
para traducir ( tr
) para convertir los dos puntos en nuevas líneas:
echo $PATH | tr : "\n"
Tiene la desventaja de usar dos procesos debido a la tubería, pero si solo estamos pirateando una terminal, ¿realmente nos importa eso?
Si desea una solución bastante permanente en su .bashrc
uso interactivo, puede usar el alias del siguiente comando path
, pero la legibilidad de esta solución es cuestionable:
alias path="echo \"${PATH//:/$'\n'}\""
Si el patrón comienza con '/', todas las coincidencias del patrón se reemplazan con una cadena. Normalmente solo se reemplaza el primer partido.
El comando anterior sustituye los dos puntos con nuevas líneas utilizando la expansión de parámetros de Shell de Bash :
${parameter/pattern/string}
Para explicarlo:
# v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
# ^^ ^^^^^----string, $ required to get newline character.
# \----------pattern, / required to substitute for *every* :.
Buena suerte recordando esto cuando solo estás pirateando la línea de comando, si no lo has aliasado, sin embargo.
Alternativamente, un enfoque bastante compatible, legible y comprensible que no se base en nada más que el shell es usar la siguiente función (sugiero en su .bashrc
).
La siguiente función convierte temporalmente el separador de campo interno (o de entrada) (IFS) en dos puntos, y cuando se le da una matriz printf
, se ejecuta hasta que la matriz se agote:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
Este método de creación de la función , IFS
y printf
se proporcionan para por posix, así que debería funcionar en la mayoría posix-como conchas (especialmente DASH, que Ubuntu generalmente alias como sh
).
¿Deberías usar Python para esto? Tú podrías. Este es el comando Python más corto que se me ocurre para esto:
python -c "print('\n'.join('${PATH}'.split(':')))"
o solo Python 3 (¿y quizás más legible?):
python3 -c "print(*'${PATH}'.split(':'), sep='\n')"
También deberían funcionar en cualquier entorno de shell habitual, siempre que tenga Python.
Esta solución es más simple que las soluciones Java , C , go y awk :
$ LPATH=$PATH wine cmd /c echo %LPATH::=$'\n'% 2> /dev/null
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin
Aquí hay otra gran posibilidad:
$ 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
Esto requeriría instalar algunas dependencias:
sudo apt-get install openjdk-8-jdk-headless bsh