Як відобразити контури в $ PATH окремо


45

Я не можу зрозуміти, як перелічити різні шляхи $PATHокремо, щоб вони виглядали так:

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

тощо.

Хтось знає правильну змінну для цього?


Кожен шлях повинен бути на окремому рядку
HankG

Що слід надрукувати, якщо ваші шляхи містять нові рядки?
Martijn


Відповіді:


57

Спробуйте sed:

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

Або tr:

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

Або python:

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

Тут все вищезазначене замінить усі події :новими рядками \n.


Варіація вашого питонського підходу:python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
Сергій Колодяжний

Ще одна варіація Python, начебто хакі: python -c "print r'$PATH'.replace(':', '\n')"(використання
необмеженої

3
trпрацював на мене (на mac, btw). Дякую.
Майк С.

Для тих, як я, які хочуть додати їх до своїх .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. Як називається його, щоб я міг шукати в Інтернеті додаткову інформацію про нього.
Tulains Córdova

3
Перейдіть за посиланням (Розширення параметрів) у моїй відповіді та прокрутіть вниз до останнього другого розділу під назвою:${parameter/pattern/string}
Сайрус

27

Використання IFS:

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

IFSмістить символи, на які bash робить розбиття, тому a IFSз :робить bash split розширенням $PATHна :. printfцикли аргументів за рядком формату, поки аргументи не будуть вичерпані. Нам потрібно вимкнути глобалізацію (розширення підстановки), використовуючи, 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.

Чи не буде цього варіанту, наприклад, 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виклику. Тут сценарій розділяє свій вклад на, :а потім петлює над кожним розділеним елементом і друкує його.

    $ 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 Compatible Regular Expressions (PCRE). Режекс шукає відрізки non- :( [^:]+), які слідують або за початком рядка ( ^), або за :символом. Це \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в шістнадцятковій спробі (спробуйте printf '\x3a\n'). -lРобить три речі. По-перше, він видаляє роздільник запису вхідних даних ( $/) з кінця кожного рядка - ефективно видаляючи :тут - і по-друге, він встановлює роздільник записів на виході ( $\) на будь-яке вісімкове або шістнадцяткове значення, яке йому задано ( 012є \n). Якщо $\це визначено, він додається до кінця кожного printдзвінка, тому це призведе до додавання нового рядка до кожного print.

-peБуде р Рінту кожен вхідний лінії після застосування сценарію дається -e. Тут немає сценарію, оскільки вся робота виконується за допомогою прапорців опцій, як описано вище!


Ваші перлинні вкладиші недостатньо затьмарені! Ось версія , де немає коди для -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. Дивіться перлрун . Приємні приклади.
7сторіччя

@ 7stud вау, це справді геніально, спасибі! Безсоромно вкрадено та додано до моєї відповіді (я припускаю, що ви не заперечуєте, не соромтесь опублікувати її як відповідь, і я видалю її). І дякую за -Fінформацію. Я використовував у -Fпоєднанні з -anроками, я ніколи не зрозумів, що один мав на увазі інших. До речі, я бачив, як Серг згадував Code Golf , але, думаю, вам також сподобається Unix & Linux, якщо ви займаєтесь подібними справами.
terdon

Гей, дякую. Одне уточнення щодо цього твердження: Нарешті, -lтакож додається роздільник записів вихідних даних, що надається в кінці кожного друку. Фактично, друк завжди додає роздільник запису виводу $/, в кінець рядка - якщо визначено роздільник записів на вихід. За замовчуванням це значення undef. Так -lвстановлюється jus $/, і це призводить до того, що друк додає новий рядок до кінця рядка.
7сторіччя

Я припускаю, що ви не проти - зовсім. :)
7stud

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 ($; має значення за замовчуванням нуль, яке розбивається на пробіли). -aвикликає $ _. split, де $ _ - рядок, зчитувана з використанням get ()) і присвоює отриманий масив $F.
7stud

@ 7stud ей, спасибі! :) Не знав, що там є -Fпрапор - я тільки починаю з Рубі, тому роблю справи трохи грубо.
Сергій Колодяжний

Ні, це незрозумілі речі. Ваш один лайнер дуже читабельний, і чіткість повинна щоразу козирнути.
7сторіччя

Ха-ха. Я зрозумів, вкорочення: ruby -0072 -ne 'puts chomp' <<<$PATH. Пояснення: -0встановлює роздільник запису вхідних даних (вкажіть символ у восьмеричному форматі; 072 - двокрапка). Рубі використовує $ _ способами, схожими на Perl. Метод get () (використовується в -nциклі) встановлює $ _ для поточного рядка, який читається. І chomp()без аргументу chomps $ _. Мені все одно подобається ваша. :)
7stud

@ 7stud насправді, той, який ви розмістили раніше, із -Fпрапором, коротший. Якщо ви це зробите, echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c то мені кажуть, що це 271 байт, але той, який має восьмеричне число, - це 276. Це, звичайно, для всієї команди, якщо ми розглянемо лише сам код puts $F, явно коротше. :) До речі, ви знаєте про Code Golf ? Це сайт для розробки програм загадок на найменшу кількість байтів. Є питання, пов'язане з цим: codegolf.stackexchange.com/q/96334/55572
Сергій Колодяжний

5

Напевно, єдиний спосіб, про який не згадували, - це те, як я його використовую роками:

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

тож у свій .profile або .bash_profile чи будь-що інше ви можете додати:

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


1
Ця відповідь вже згадував це ..
heemayl

Так, але мені подобається пропозиція для псевдоніма.
7stud

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
Kaz Wolfe

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

Я використовую "Баш-шлях шляху" Стівена Коллієра (див. Його статтю в Linux Journal ). Це дозволяє мені використовувати "розділений двокрапкою список" як тип даних в програмуванні оболонок. Наприклад, я можу створити список усіх каталогів у поточному каталозі:

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

Потім listpath -p dirsвиробляє список.


2

Пояснення відповіді @Cyrus

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

Примітки:

Цитування ANSI-C - це пояснює $ 'some \ ntext'

Розширення параметра оболонки - це пояснює $ {параметр / шаблон / рядок}, Якщо шаблон починається з '/', всі збіги шаблону замінюються рядком.

Отже, ми маємо:

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

1

Ще один спосіб AWK - трактувати кожен каталог як окремий запис , а не як окреме поле .

awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"

Я вважаю цей синтаксис особливо інтуїтивним. Але, якщо вам подобається, ви можете скоротити її, зробивши print $0неявну (це дію за замовчуванням і 1оцінюється як істинне, внаслідок чого це робиться для кожного рядка):

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його та перекладіть,tr щоб перекласти ( ), щоб перетворити колонки на нові рядки:

echo $PATH | tr : "\n"

Має недолік використання двох процесів через трубу, але якщо ми просто злому в терміналі, чи нас справді це хвилює?

Розширення параметра оболонки Баша

Якщо ви хочете досить .bashrcінтерактивне рішення у вашому інтерактивному використанні, ви можете вказати наступну команду path, але читабельність цього рішення сумнівна:

alias path="echo \"${PATH//:/$'\n'}\""

Якщо шаблон починається з '/', всі збіги шаблону замінюються рядком. Зазвичай замінюється лише перший матч.

Вищевказана команда замінює двокрапки на нові рядки, використовуючи розширення параметру оболонки Баша :

${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 and 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 and 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.