Как отобразить пути в $PATH отдельно
Я не могу понять, как перечислить различные пути в $PATH
отдельно, чтобы они выглядели так:
/bin
/usr/bin
/usr/local/bin
и т.п.
Кто-нибудь знает правильную переменную для этого?
16 ответов
Пытаться sed
:
$ sed 's/:/\n/g' <<< "$PATH"
Или же tr
:
$ tr ':' '\n' <<< "$PATH"
Или же python
:
$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"
Здесь все вышеперечисленное заменит все вхождения :
с новыми линиями \n
,
Используйте расширение параметров bash:
echo "${PATH//:/$'\n'}"
Это заменяет все :
в $PATH
по новой строке (\n
) и печатает результат. Содержание $PATH
остается неизменной.
Если вы хотите заменить только первый :
, удалите вторую косую черту: echo -e "${PATH/:/\n}"
Используя IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
содержит символы, по которым bash выполняет разбиение, поэтому IFS
с :
делает Bash сплит расширение $PATH
на :
, printf
Зацикливает аргументы над строкой форматирования, пока аргументы не будут исчерпаны. Нам нужно отключить глобирование (расширение по шаблону), используя set -f
так что подстановочные знаки в именах каталогов PATH не раскрываются.
С помощью xargs
:
xargs -n1 -d: <<< $PATH
От 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 | tr ":" "\n"
Итак, в ваш.profile или.bash_profile или что-то еще вы можете добавить:
alias path='echo $PATH | tr ":" "\n"'
В этом ответе:
- С
- питон
- Рубин
- Альтернативный awk
1. С
Поскольку все языки сценариев уже заняты, я перейду к C. Довольно просто получить переменные среды с get_env()
функция (см. документацию библиотеки GNU C). Остальное - просто манипуляция персонажем.
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 через аргументы командной строки sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
3. Рубин
Ruby не поставляется с Ubuntu по умолчанию, в отличие от компилятора C и интерпретатора Python, но если вы когда-нибудь будете его использовать, решение в Ruby будет таким:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
Как предлагает 7stud (спасибо большое!) В комментариях, это также можно сократить с помощью
ruby -F: -ane 'puts $F' <<<$PATH
и так
ruby -0072 -ne 'puts chomp' <<<$PATH
4. Альтернативный awk
Мы можем использовать split()
функция, чтобы разбить строку, прочитанную в массив, и использовать for-each
цикл для распечатки каждого элемента в отдельной строке.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
Вот эквивалент в 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
Вот еще несколько подходов. Я использую PATH
с каталогами, содержащими обратную косую черту, пробелы и даже новую строку, чтобы показать, что они должны работать с чем угодно (кроме cut
тот, который терпит неудачу на новых строках):
$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even
new lines
Некоторые способы Perl:
$ perl -pe 's/:/\n/g' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
-p
означает "печатать каждую строку ввода после применения скрипта, заданного-e
Msgstr "Сценарий использует оператор подстановки (s/oldnew/
) заменить все:
с символами новой строки.$ perl -lne 'print for split /:/' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
-l
добавляет новую строку к каждомуprint
вызов. Здесь скрипт разделяет свой вход на:
а затем зацикливается на каждом элементе split и печатает его.$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
-a
маркиperl
вести себя какawk
: он разделит каждую из своих строк ввода на символ, заданный-F
(так:
и сохраняем результат в массиве@F
,$"
это специальная переменная Perl, "разделитель списка", значение которой печатается между каждым элементом печатного списка. Так что установка его на новую строку сделаетprint @list
распечатать каждый элемент@list
а затем перевод строки. Здесь мы используем его для печати@F
,$ perl -F: -ane 'print join "\n", @F' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
Та же идея, что и выше, только меньше в гольфе. Вместо того, чтобы использовать
$"
мы явноjoin
Создание массива с символами новой строки, а затем печать.просто
grep
с магией PCRE:$ grep -oP '(^|:)\K[^:]+' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
-o
маркиgrep
печатать только совпадающую часть каждой строки, поэтому каждое совпадение печатается на отдельной строке.-P
включает Perl-совместимые регулярные выражения (PCRE). Регулярное выражение ищет отрезки не:
([^:]+
), которые следуют либо за началом строки (^
) или:
персонаж.\K
это трюк PCRE, который означает "отбросить что-либо подходящее до этого момента" и используется здесь, чтобы избежать печати:
также.И
cut
решение (это не работает на новых строках, но может иметь дело с обратными слешами и пробелами):$ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH" /bin usr/bin/ /usr/local/bin /some\ horrible thing /even new lines
Используемые опции
-d:
который устанавливает входной разделитель в:
,-f 1-
что означает печать всех полей (от 1-го до конца) и--output-delimiter=$'\n'
который устанавливает, ну, выходной разделитель.$'\n'
ANSI C цитирование и способ печати символа новой строки в оболочке.
Во всех приведенных выше примерах я использую строку bash (и некоторых других оболочек) здесь (<<<
) оператор для передачи строки в качестве ввода в программу. Так command <<<"foo"
эквивалентно echo -n "foo" | command
, Обратите внимание, что я всегда цитирую"$PATH"
без кавычек оболочка съела бы символ новой строки.
@ 7stud дал другой подход в комментариях, который слишком хорош, чтобы не включать:
$ perl -0x3a -l012 -pe '' <<<"$PATH"
Это то, что известно как гольф. -0
определяет входной разделитель записей в виде восьмеричного или шестнадцатеричного числа. Это то, что определяет "линию" и ее значение по умолчанию \n
, символ новой строки. Здесь мы устанавливаем это :
который x3a
в шестнадцатеричном (попробуйтеprintf '\x3a\n'
). -l
делает три вещи. Сначала он удаляет разделитель входной записи ($/
) с конца каждой строки - эффективно удаляя:
здесь - и во-вторых, он устанавливает разделитель выходной записи ($\
) любому восьмеричному или шестнадцатеричному значению, которое ему дается (012
является \n
). Если $\
определяется, он добавляется в конце каждогоprint
вызов, так что это приведет к добавлению новой строки к каждомуprint
,
-pe
будет печатать каждую строку ввода после применения скрипта, заданного -e
, Здесь нет сценария, потому что вся работа выполняется с помощью флагов, как описано выше!
Нам нужно больше Java!
public class GetPathByLine {
public static void main(String[] args) {
for (String p : System.getenv("PATH").split(":")) {
System.out.println(p);
}
}
}
Сохранить это в GetPathByLine.java
и скомпилируйте, используя:
javac GetPathByLine.java
Бежать с:
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
Через awk.
echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'
Через питона.
$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
for i in line.split(":"):
print(i)'
Обратите внимание, что отступы очень важны в Python.
Я использую "Функции пути Bash" Стивена Коллайера (см. Его статью в Linux Journal). Это позволяет мне использовать "список через двоеточие" в качестве типа данных в программировании оболочки. Например, я могу создать список всех каталогов в текущем каталоге:
dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done
Затем, listpath -p dirs
производит список.
Объяснение для ответа @Cyrus
echo "${PATH//:/$'\n'}"
Заметки:
Цитирование ANSI-C - объясняет $'some\ntext'
Расширение параметра оболочки - оно объясняет ${параметр / шаблон / строку}. Если шаблон начинается с '/', все совпадения шаблона заменяются строкой.
Итак, мы имеем:
- шаблон /: который начинается с '/', чтобы заменить все совпадения
- строка $'\n', которая заключена в сокращение $ anytext для обработки символа новой строки (\n).
Другой способ AWK - рассматривать каждый каталог как отдельную запись, а не как отдельное поле.
awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
Я нахожу этот синтаксис особенно интуитивным. Но, если хотите, вы можете сократить его, сделав print $0
неявное (это действие по умолчанию, и 1
оценивается как true, в результате чего это делается для каждой строки):
awk 'BEGIN{RS=":"} 1' <<<"$PATH"
По умолчанию в качестве разделителя входных и выходных записей AWK используется перевод строки. Установив разделитель входной записи (RS
) чтобы :
перед прочтением ввода AWK автоматически анализирует разделенный двоеточиями $PATH
в составные имена каталогов. AWK расширяется $0
для каждой записи в целом, символ новой строки остается разделителем выходной записи, без зацикливания или gsub
нужно.
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 часто используется для анализа записей в отдельных полях, но для этого не нужно просто составлять список имен каталогов.
Это работает даже для ввода, содержащего пробелы (пробелы и табуляции), даже несколько последовательных пробелов:
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de fg:h'
ab c
de fg
h
То есть, если вы не заставите AWK перестроить запись (см. Ниже), нет проблем с наличием пробелов или табуляций (разделителей полей по умолчанию) на входе. Ваш PATH
вероятно, не содержит пробелов в системе Ubuntu, но если это так, это все равно будет работать.
В качестве дополнительного примечания стоит упомянуть, что способность AWK интерпретировать запись как набор полей становится полезной для связанной проблемы построения таблицы компонентов каталога:
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
Любопытный $1=$1
назначение служит для того, чтобы заставить AWK перестроить запись.
(Это, вероятно, более полезно для случаев, когда для компонентов требуется дополнительная обработка, чем для показанного точного примера простой печати таблицы.)
Как отобразить пути в $PATH отдельно
Это мои предпочтительные способы сделать это, основываясь на моих соответствующих сценариях использования и заботах о совместимости и использовании ресурсов.
tr
Во-первых, если вам нужно быстрое, легко запоминающееся и читаемое решение, просто откройте эхо PATH
и трубку это перевести ( tr
) превратить двоеточия в новые строки:
echo $PATH | tr : "\n"
Недостатком является использование двух процессов из-за конвейера, но если мы просто взломали терминал, нас это действительно волнует?
Расширение параметров оболочки Bash
Если вы хотите довольно постоянное решение в вашем .bashrc
для интерактивного использования, вы можете псевдоним следующей команды path
, но читаемость этого решения сомнительна:
alias path="echo \"${PATH//:/$'\n'}\""
Если шаблон начинается с '/', все совпадения шаблона заменяются строкой. Обычно заменяется только первый матч.
Приведенная выше команда заменяет двоеточие символами новой строки, используя расширение параметров оболочки Bash:
${parameter/pattern/string}
Чтобы объяснить это:
# v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
# ^^ ^^^^^----string, $ required to get newline character.
# \----------pattern, / required to substitute for *every* :.
Удачи, помня об этом, когда вы просто взламываете командную строку, если вы еще не добавили псевдоним.
IFS, проверено в Bash и Dash
В качестве альтернативы, достаточно кросс-совместимый, читаемый и понятный подход, который не зависит ни от чего, кроме оболочки, использует следующую функцию (я предлагаю в вашей .bashrc
.)
Следующая функция временно делает Внутренний (или Входной) Разделитель Полей (IFS) двоеточием, и когда массив передается printf
, он выполняется, пока массив не будет использован:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
Этот метод создания функции, IFS
, а также printf
предоставляются posix, поэтому он должен работать в большинстве posix-подобных оболочек (особенно в Dash, которые в Ubuntu обычно используют как sh
).
питон
Вы должны использовать Python для этого? Вы могли бы. Это самая короткая команда Python, о которой я могу подумать:
python -c "print('\n'.join('${PATH}'.split(':')))"
или только Python 3 (и, возможно, более читабельный?):
python3 -c "print(*'${PATH}'.split(':'), sep='\n')"
Они также должны работать в любой обычной оболочке, если у вас есть Python.
Это решение проще, чем Java, C, go и awk:
$ LPATH=$PATH wine cmd /c echo %LPATH::=$'\n'% 2> /dev/null
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin
Вот еще одна отличная возможность:
$ 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
Это потребует установки некоторых зависимостей:
sudo apt-get install openjdk-8-jdk-headless bsh
Это работает в Git Bash для Windows:
python -c "import os; print os.environ['PATH'].replace(';', '\n')"
Он красиво разбивает строки:
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