Как отобразить пути в $ PATH отдельно

45

Я не могу понять, как перечислить различные пути в $PATHотдельности, чтобы они выглядели так:

/bin
/usr/bin
/usr/local/bin

и т.п.

Кто-нибудь знает правильную переменную для этого?

HankG
источник
Каждый путь должен быть на отдельной строке, пожалуйста
HankG
Что должно быть напечатано, если ваши пути содержат переводы строк?
Мартин
Межсайтовый дубликат unix.stackexchange.com/q/80151/85039
Сергей Колодяжный

Ответы:

57

Попробуй sed:

$ sed 's/:/\n/g' <<< "$PATH"

Или tr:

$ tr ':' '\n' <<< "$PATH"

Или python:

$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"

Здесь все вышеперечисленное заменит все вхождения :новыми строками \n.

heemayl
источник
Вариация на подходе к вашему питону:python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
Сергей Колодяжный
Еще одна разновидность Python, вроде хакки: python -c "print r'$PATH'.replace(':', '\n')"(с использованием необработанной строки в случае обратной косой черты)
wjandrea
3
trработал для меня (на Mac, кстати). Спасибо.
Майк С.
Для тех, как я, кто хочет добавить это к своим .bash_profile, добавьте это так:alias path='tr ":" "\n" <<< "$PATH"'
Майк С.
63

Используйте расширение параметров bash :

echo "${PATH//:/$'\n'}"

Это заменяет олл- :ин $PATHновой строкой ( \n) и печатает результат. Содержание $PATHостается без изменений.
Если вы хотите заменить только первое :, удалите вторую косую черту:echo -e "${PATH/:/\n}"

Кир
источник
3
Я думаю, что это лучшее решение, потому что оно сделано в чистом виде .
ryanmjacobs
1
@ryanmjacobs слегка любопытно: как вы думаете, что использует мое решение? : D
Муру
1
пожалуйста, объясните, как это работает.
Тулаинс Кордова
Как называется такая операция? Это похоже на sed, но это не sed. Как это называется, поэтому я могу искать в Интернете больше информации об этом.
Тулаинс Кордова
3
Перейдите по ссылке (Расширение параметров) в моем ответе и прокрутите вниз до последней второй секции, которая называется:${parameter/pattern/string}
Cyrus
27

Используя IFS:

(set -f; IFS=:; printf "%s\n" $PATH)

IFSсодержит символы, по которым bash выполняет разбиение, поэтому команда IFSwith :делает bash-разбиение расширением $PATHon :. printfЗацикливает аргументы над строкой форматирования, пока аргументы не будут исчерпаны. Нам нужно отключить использование globbing (подстановочные символы), set -fчтобы подстановочные знаки в именах каталогов PATH не расширялись.

Мур
источник
2
Это работает правильно с обратной косой чертой и пробелами!
heinrich5991
14

Использование 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.
souravc
источник
Будет ли изменение в этом, например, echo $PATH | xargs -n1 -d: echoизлишним или это не имеет значения?
Сергей Колодяжный
@Serg echo $PATH | xargs -n1 -d: сделает то же самое для вас, но вы будете использовать еще одну оболочку. Первый из них оценит echo $PATHи перенаправит вывод в следующую оболочку, чтобы сделать все остальное.
souravc
7

Вот эквивалент в 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
Натан Осман
источник
7

Вот еще несколько подходов. Я использую 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». Скрипт использует оператор подстановки ( 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 magic:

    $ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines
    

    В -oмарки grepпечатать только совпадающую часть каждой строки, поэтому каждый матч печатается на отдельной строке. -PПозволяет Perl Compatible Regular Expressions (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 (и некоторых других оболочек) здесь string ( <<<) для передачи строки в качестве входных данных для программы. Так command <<<"foo"эквивалентно echo -n "foo" | command. Обратите внимание, что я всегда цитирую "$PATH", без кавычек оболочка съела бы символ новой строки.


@ 7stud дал другой подход в комментариях, который слишком хорош, чтобы не включать:

$ perl -0x3a -l012 -pe '' <<<"$PATH"

Это то, что известно как гольф . -0Определяет входной разделитель записей в виде восьмеричного или шестнадцатеричного числа. Это то, что определяет «строку» и ее значение по умолчанию - \nсимвол перевода строки. Здесь мы устанавливаем его к :который x3aв шестнадцатеричном (TRY printf '\x3a\n'). Это -lделает три вещи. Во-первых, он удаляет разделитель входных записей ( $/) в конце каждой строки, эффективно удаляя :здесь, а во-вторых, он устанавливает разделитель выходных записей ( $\) на любое восьмеричное или шестнадцатеричное значение, которое ему дано ( 012есть \n). Если $\он определен, он добавляется в конец каждого printвызова, поэтому к каждому добавляется новая строка print.

-peБудет р Ринт каждый входной линии после применения сценария дается -e. Здесь нет сценария, потому что вся работа выполняется с помощью флагов, как описано выше!

Тердон
источник
Ваш Perl один лайнер не достаточно неясен! Вот версия , где нет коды для -e переключателя выполнить , потому что другие коммутаторы обрабатывать все: perl -0x3a -l012 -pe '' <<<$PATH. Объяснение: -0устанавливает разделитель входной записи (указанный в шестнадцатеричной / восьмеричной нотации, x3A - двоеточие), -lделает две вещи: 1) разбивает разделитель входной записи, 2) устанавливает разделитель выходной записи, если он указан (в восьмеричной записи) 012 - новая строка). А -pцикл выводит значение $ _, которая будет каждая линии читать.
7stud
Кроме того, обратите внимание , что ваши примеры использования -Fможно устранить -aи -nфлаги, а -F превращает те автоматически: perl -F: -e 'print(join "\n", @F);' <<<$PATH. Смотрите Perlrun . Хорошие примеры.
7
@ 7-й класс, это действительно здорово, спасибо! Бесстыдно украден и добавлен в мой ответ (я полагаю, вы не против, не стесняйтесь опубликовать его как ответ самостоятельно, и я его удалю). И спасибо за -Fинформацию. Я использую в -Fсочетании с -anгодами, я никогда не понимал, что одно подразумевает другие. Между прочим, я видел, как Серж упомянул Code Golf , но я думаю, что вам также понравятся Unix и Linux, если вы занимаетесь этим.
Terdon
Эй спасибо Одно уточнение об этом утверждении: Наконец, -lтакже добавляется разделитель выходных записей, который дается в конце каждого вызова печати. Фактически print всегда добавляет разделитель выходной записи $/к концу строки, если разделитель выходной записи определен. По умолчанию это undef. Так что -ljus устанавливает $/, и это заставляет print добавить символ новой строки в конец строки.
7
Я полагаю, вы не возражаете - совсем нет. :)
7
6

Вероятно, единственный способ, который не был упомянут, это то, как я использовал его годами:

echo $PATH | tr ":" "\n"

Итак, в ваш .profile или .bash_profile или что-то еще вы можете добавить:

alias path='echo $PATH | tr ":" "\n"'

раздолбай
источник
1
Этот ответ уже упоминал об этом ..
Heemayl
Да, но мне нравится предложение для псевдонима.
7
6

В этом ответе:

  1. С
  2. питон
  3. Рубин
  4. Альтернативный 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
Сергей Колодяжный
источник
1
Хороший рубиновый пример. putsавтоматически печатает элементы массива на отдельных строках! Вы также можете сделать так, чтобы переключатели делили: ruby -F: -ane 'puts $F' <<<$PATH Объяснение: -Fустанавливает $;указанный символ, который является разделителем по умолчанию, используемым String :: split ($; имеет значение по умолчанию nil, которое разделяется на пробел). -aвызывает $ _. split, где $ _ - строка, считываемая с использованием gets ()), и присваивает результирующий массив $F.
7
@ 7stud эй, спасибо! :) Не знал, что есть -Fфлаг - я только начинаю с Руби, поэтому делаю что-то немного грубым.
Сергей Колодяжный
Нет, это неясные вещи. Ваш единственный вкладыш очень удобочитаемый, и ясность должна превосходить краткость каждый раз.
7
Хах. Я разобрался с более коротким ruby -0072 -ne 'puts chomp' <<<$PATH. Объяснение: -0устанавливает разделитель входной записи (укажите символ в восьмеричном формате; 072 - двоеточие). Ruby использует $ _ аналогично Perl. Метод gets () (используемый в -nцикле) устанавливает $ _ для текущей строки, которая читается. И chomp()без аргумента chomps $ _. Мне все еще нравится твой лучше. :)
7
@ 7stud на самом деле, тот, который вы опубликовали ранее, с -Fфлагом, короче. Если вы это сделаете, echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c это скажет мне, что это 271 байт, но тот, у которого восьмеричное число равно 276. Это для всей команды, конечно, если мы рассмотрим только код, puts $Fон явно короче. :) Кстати, вы знаете о Code Golf ? Это сайт для решения головоломок с минимальным количеством байтов. Есть вопрос, связанный с этим: codegolf.stackexchange.com/q/96334/55572
Сергей Колодяжный
4

Нам нужно больше 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
Каз Вулф
источник
Вау, это излишне. Вы можете сделать это в одной строке в Python 3:python3 -c "import os; [print(p) for p in os.getenv('PATH').split(':')]"
wjandrea
1
@wjandrea В этом все дело! : D
Каз Вулф
3

Через 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.

Авинаш Радж
источник
Короче awk:echo $PATH | awk '{gsub(/\:/,"\n");print}'
Сергей Колодяжный
Я не уверен, почему вы беспокоитесь, fileinputкогда вы могли бы просто использовать input:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
wjandrea
2

Я использую «Функции пути Bash» Стивена Коллайера (см. Его статью в Linux Journal ). Это позволяет мне использовать «список через двоеточие» в качестве типа данных в программировании оболочки. Например, я могу создать список всех каталогов в текущем каталоге:

dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done  

Затем listpath -p dirsвыдает список.

waltinator
источник
2

Объяснение для ответа @Cyrus

echo "${PATH//:/$'\n'}"

Заметки:

Цитирование ANSI-C - объясняет $ 'some \ ntext'

Расширение параметра оболочки - оно объясняет $ {параметр / шаблон / строку}. Если шаблон начинается с '/', все совпадения шаблона заменяются строкой.

Итак, мы имеем:

  1. шаблон /: который начинается с '/', чтобы заменить все совпадения
  2. строка $ '\ n', которая заключена в сокращение $ anytext для обработки символа новой строки (\ n).
victorq10
источник
1

Другой способ 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 перестроить запись .

(Это, вероятно, более полезно для случаев, когда для компонентов требуется дополнительная обработка, чем для показанного точного примера простой печати таблицы.)

Элия ​​Каган
источник
0

Как отобразить пути в $ PATH отдельно

Это мои предпочтительные способы сделать это, основываясь на моих соответствующих сценариях использования и заботах о совместимости и использовании ресурсов.

tr

Во-первых, если вам нужно быстрое, легко запоминающееся и читаемое решение, просто введите эхо PATHи направьте его в translate ( 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-подобных оболочек (особенно тире, который Ubuntu обычно псевдонимы sh).

питон

Вы должны использовать Python для этого? Ты мог бы. Это самая короткая команда Python, о которой я могу подумать:

python -c "print('\n'.join('${PATH}'.split(':')))"

или только Python 3 (и, возможно, более читабельный?):

python3 -c "print(*'${PATH}'.split(':'), sep='\n')"

Они также должны работать в любой обычной оболочке, если у вас есть Python.

Аарон Холл
источник
0

Это решение проще, чем 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
Gungwald
источник