I cannot figure out how to list the various paths in $PATH
separately so that they look like this:
/bin
/usr/bin
/usr/local/bin
How can this be done?
I cannot figure out how to list the various paths in $PATH
separately so that they look like this:
/bin
/usr/bin
/usr/local/bin
How can this be done?
You can do this with any one of the following commands, which substitutes all occurrences of :
with new lines \n
.
sed
:
$ sed 's/:/\n/g' <<< "$PATH"
tr
:
$ tr ':' '\n' <<< "$PATH"
python
:
$ python -c 'import sys;print(sys.argv[1].replace(":","\n"))' "$PATH"
python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
Commented
Oct 15, 2016 at 19:02
python -c "print r'$PATH'.replace(':', '\n')"
(using a raw string in case of backslashes)
.bash_profile
, add it like this: alias path='tr ":" "\n" <<< "$PATH"'
Use bash's Parameter Expansion:
echo "${PATH//:/$'\n'}"
This replaces all :
in $PATH
by a newline (\n
) and prints the result. The content of $PATH
remains unchanged.
If you only want to replace the first :
, remove second slash: echo -e "${PATH/:/\n}"
${parameter/pattern/string}
Using IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
holds the characters on which bash does splitting, so an IFS
with :
makes bash split the expansion of $PATH
on :
. printf
loops the arguments over the format string until arguments are exhausted.
We need to disable globbing (wildcard expansion) using set -f
so that wildcards in PATH directory names don't get expanded.
Using xargs
:
xargs -n1 -d: <<< $PATH
From 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
be redundant or it doesn't matter ?
Commented
Apr 3, 2015 at 7:59
echo $PATH | xargs -n1 -d:
will do the same thing for you but you will be using one more shell. The first one will evaluate echo $PATH
and pipe output to next shell to do the rest.
Commented
Apr 7, 2015 at 12:46
Probably the only way that hasn't been mentioned is the way i've been using it for years:
echo $PATH | tr ":" "\n"
so, in your .profile or .bash_profile or whatever, you can add:
alias path='echo $PATH | tr ":" "\n"'
echo %PATH% | tr ";" "\n"
Since all the scripting languages have been taken already, I'll go with C. It's quite easy to get environment variables with get_env()
function ( see GNU C Library documentation). The rest is simply character manipulation
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
But also because "why not" , here's alternative python version via command line arguments sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
Ruby doesn't come with Ubuntu by default, unlike C compiler and Python interpreter, but if you ever find yourself using it, the solution in Ruby would be this:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
As suggested by 7stud (Thank you very much !) in the comments, this can also be shortened with
ruby -F: -ane 'puts $F' <<<$PATH
and this way
ruby -0072 -ne 'puts chomp' <<<$PATH
We can utilize split()
function to break down the line read into array, and use for-each
loop to print out each item on separate line.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
automatically prints the elements of an array on separate lines! You can also make the switches do the split: ruby -F: -ane 'puts $F' <<<$PATH
Explanation: -F
sets $;
to the specified character, which is the default separator used by String::split ($; has a default value of nil, which splits on whitespace). -a
calls $_.split, where $_ is a line read in using gets()) and assigns the resulting array to $F
.
-F
flag - I am just starting out with Ruby, so doing things slightly crude way.
Commented
Jan 14, 2017 at 4:42
ruby -0072 -ne 'puts chomp' <<<$PATH
. Explanation: -0
sets the input record separator(specify a character in octal format; 072 is a colon). Ruby employs $_ in ways similar to Perl. The gets() method (used in the -n
loop) sets $_ to the current line that's read in. And chomp()
without an arg, chomps $_. I still like yours better. :)
-F
flag, is shorter. If you do echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
that tells me it's 271, bytes, but the one with octal number is 276. That's for the whole command, of course, If we consider only the code itself puts $F
is clearly shorter. :) By the way , do you know about Code Golf ? It's the site for solutions to programming puzzles in shortest number of bytes. There's a question related to this one : codegolf.stackexchange.com/q/96334/55572
Commented
Jan 14, 2017 at 11:36
Here's the equivalent in 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
Here are a few more approaches. I'm using a PATH
with directories containing backslashes, spaces and even a new line to show that they should work with anything (except the cut
one which fails on newlines):
$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even
new lines
Some Perl ways:
$ perl -pe 's/:/\n/g' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
The -p
means "print every input line after applying the script given by -e
". The script is using the substitution operator (s/oldnew/
) to replace all :
with newlines.
$ perl -lne 'print for split /:/' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
The -l
adds a newline to each print
call. Here, the script is splitting its input on :
and then loops over each split element and prints it.
$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
The -a
makes perl
behave like awk
: it will split each of its input lines on the character given by -F
(so :
, here) and save the result in the array @F
. The $"
is a special Perl variable, the "list separator", whose value is printed between each element of a printed list. So setting it to a newline will make print @list
print each element of @list
and then a newline. Here, we're using it to print @F
.
$ perl -F: -ane 'print join "\n", @F' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Same idea as above, just less golfed. Instead of using $"
, we are explicitly join
ing the array with newlines and then printing.
Simple grep
with PCRE magic:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
The -o
makes grep
print only the matching portion of each line, so each match is printed on a separate line. The -P
enables Perl Compatible Regular Expressions (PCRE). The regex is looking for stretches of non-:
([^:]+
) that follow either the beginning of the line (^
) or a :
character. The \K
is a PCRE trick that means "discard anything matched before this point" and is used here to avoid printing the :
as well.
And a cut
solution (this one fails on newlines, but can deal with backslashes and spaces):
$ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
The options used are -d:
which sets the input delimiter to :
, -f 1-
which means print all fields (from the 1st to the end) and --output-delimiter=$'\n'
which sets the, well, output delimiter. The $'\n'
is ANSI C quoting and is a way to print a newline character in the shell.
In all of the above examples, I am using bash's (and some other shells') here string (<<<
) operator to pass a string as input to a program. So command <<<"foo"
is equivalent to echo -n "foo" | command
. Note that I am always quoting "$PATH"
, without the quotes, the shell would have eaten the newline character.
@7stud gave another approach in the comments that's just too good not to include:
$ perl -0x3a -l012 -pe '' <<<"$PATH"
That's what's known as golfing. The -0
specifies the input record separator as an octal or hexadecimal number. This is what defines a "line" and its default value is \n
, a newline character. Here, we're setting it to a :
which is x3a
in hex (try printf '\x3a\n'
). The -l
does three things. First it removes the input record separator ($/
) from the end of each line—effectively removing the :
here—and second, it sets the output record separator ($\
) to whatever octal or hex value it is given (012
is \n
). If $\
is defined, it is added to the end of each print
call, so this will result in a newline appended to each print
.
The -pe
will print each input line after applying the script given by -e
. Here there is no script because all the work is done by the option flags as described above!
perl -0x3a -l012 -pe '' <<<$PATH
. Explanation: -0
sets the input record separator (specified in hex/octal notation, x3A is a colon), -l
does two things: 1) it chomps the input record separator, 2) it sets the output record separator if one is specified (in octal notation, 012 is a newline). A -p
loop prints out the value of $_ , which will be each line read in.
-F
info. I've been using -F
combined with -an
for years, I never realized the one implied the others. By the way, I saw Serg mentioned Code Golf, but I think you'd also enjoy Unix & Linux if you're into this sort of thing.
-l
also adds the output record separator given to the end of each print call. In fact, print always adds the output record separator, $/
, to the end of a string--if the output record separator is defined. By default it is is undef. So -l
jus sets $/
, and that causes print to add the newline to the end of the string.
We need more Java!
public class GetPathByLine {
public static void main(String[] args) {
for (String p : System.getenv("PATH").split(":")) {
System.out.println(p);
}
}
}
Save this to GetPathByLine.java
, and compile using:
javac GetPathByLine.java
Run with:
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(':')]"
Through awk.
echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'
Through python.
$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
for i in line.split(":"):
print(i)'
Note that Indentation is very important in python.
echo $PATH | awk '{gsub(/\:/,"\n");print}'
Commented
Oct 14, 2016 at 23:10
fileinput
when you could just use input
: python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
I use Stephen Collyer's "Bash Path Functions" (see his article in Linux Journal). It permits me to use the "colon separated list" as a datatype in shell programming. For example, I can produce a list of all the directories in the current directory by:
dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done
Then, listpath -p dirs
produces a list.
Explanation for @Cyrus answer
echo "${PATH//:/$'\n'}"
Notes:
ANSI-C Quoting - it explains $'some\ntext'
Shell Parameter Expansion - it explains ${parameter/pattern/string}, If pattern begins with ‘/’, all matches of pattern are replaced with string.
So we have:
Another AWK way is to treat each directory as a separate record, rather than as a separate field.
awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
I find that syntax particularly intuitive. But, if you like, you can shorten it by making the print $0
implicit (it is the default action, and 1
evaluates to true, causing it to be done for every line):
awk 'BEGIN{RS=":"} 1' <<<"$PATH"
AWK's default input and output record separator is the newline (line break). By setting the input record separator (RS
) to :
before reading the input, AWK automatically parses a colon-deliminated $PATH
into its constitutent directory names. AWK expands $0
to each whole record, the newline remains the output record separator, and no looping or gsub
is needed.
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 is often used to parse records into separate fields, but there's no need for that just to construct a list of directory names.
This works even for input containing blanks (spaces and tabs), even multiple consecutive blanks:
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de fg:h'
ab c
de fg
h
That is, unless you cause AWK to rebuild the record (see below), it's no problem to have spaces or tabs (the default field separators) in the input. Your PATH
probably doesn't contain spaces on an Ubuntu system, but if it does, this will still work.
It's worth mentioning, as a side note, that AWK's ability to interpret a record as a collection of fields becomes useful for the related problem of constructing a table of directory components:
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
The curious $1=$1
assignment serves the purpose of forcing AWK to rebuild the record.
(This is probably more useful for cases where additional processing is to be done on the components, than for the exact example shown of simply printing the table.)
How to display the paths in $PATH separately
These are my preferred ways of doing this based on my respective use-cases and concerns about compatibility and resource usage.
tr
First, if you need a quick, easy to remember, and readable solution, just echo PATH
and pipe it to translate (tr
) to turn the colons into newlines:
echo $PATH | tr : "\n"
It has the downside of using two processes because of the pipe, but if we're just hacking in a terminal, do we really care about that?
If you want a fairly permanent solution in your .bashrc
for interactive use, you can alias the following command to path
, but the readability of this solution is questionable:
alias path="echo \"${PATH//:/$'\n'}\""
If pattern begins with ‘/’, all matches of pattern are replaced with string. Normally only the first match is replaced.
The above command substitutes the colon with newlines using Bash's Shell Parameter Expansion:
${parameter/pattern/string}
To explain it:
# v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
# ^^ ^^^^^----string, $ required to get newline character.
# \----------pattern, / required to substitute for *every* :.
Good luck remembering this when you're just hacking on the command line, if you haven't aliased it, though.
Alternatively, a fairly cross-compatible, readable, and understandable approach that doesn't rely on anything other than the shell is use the following function (I suggest in your .bashrc
.)
The following function temporarily makes the Internal (or Input) Field Separator (IFS) a colon, and when an array is given to printf
, it executes until the array is used up:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
This method of function creation, IFS
, and printf
are provided for by posix, so it should work in most posix-like shells (especially Dash, which Ubuntu usually aliases as sh
).
Should you use Python for this? You could. This is the shortest Python command I can think of for this:
python -c "print('\n'.join('${PATH}'.split(':')))"
or Python 3 only (and perhaps more readable?):
python3 -c "print(*'${PATH}'.split(':'), sep='\n')"
These should work in any usual shell environment as well, so long as you have Python.
\$
escape the first $
dollar sign too? Otherwise I think this does the reformatting only once at load-time, instead of every time you run the path command.
Commented
Nov 9, 2022 at 20:27
alias path="echo \"\${PATH//:/$'\n'}\""
was the command I needed to use.
Commented
Nov 9, 2022 at 20:29
This solution is simpler than the Java, C, go and awk solutions:
$ LPATH=$PATH wine cmd /c echo %LPATH::=$'\n'% 2> /dev/null
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin
Here's another great possibility:
$ 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
This would require some dependencies to be installed:
sudo apt-get install openjdk-8-jdk-headless bsh
This works in Git Bash for Windows:
python -c "import os; print os.environ['PATH'].replace(';', '\n')"
It breaks the lines nicely:
c:\Rtools\mingw_32\bin
C:\Program Files (x86)\Intel\MPI-RT\4.1.3.045\ia32\bin
C:\Windows\system32
C:\Windows
C:\Windows\System32\Wbem
C:\Windows\System32\WindowsPowerShell\v1.0\
C:\ProgramData\chocolatey\bin
C:\Program Files (x86)\vim\vim74