Я не могу понять, как перечислить различные пути в $PATH
отдельности, чтобы они выглядели так:
/bin
/usr/bin
/usr/local/bin
и т.п.
Кто-нибудь знает правильную переменную для этого?
Я не могу понять, как перечислить различные пути в $PATH
отдельности, чтобы они выглядели так:
/bin
/usr/bin
/usr/local/bin
и т.п.
Кто-нибудь знает правильную переменную для этого?
Ответы:
Попробуй 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 -c "print r'$PATH'.replace(':', '\n')"
(с использованием необработанной строки в случае обратной косой черты)
tr
работал для меня (на Mac, кстати). Спасибо.
.bash_profile
, добавьте это так:alias path='tr ":" "\n" <<< "$PATH"'
Используйте расширение параметров bash :
echo "${PATH//:/$'\n'}"
Это заменяет олл- :
ин $PATH
новой строкой ( \n
) и печатает результат. Содержание $PATH
остается без изменений.
Если вы хотите заменить только первое :
, удалите вторую косую черту:echo -e "${PATH/:/\n}"
${parameter/pattern/string}
Используя IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
содержит символы, по которым bash выполняет разбиение, поэтому команда IFS
with :
делает bash-разбиение расширением $PATH
on :
. printf
Зацикливает аргументы над строкой форматирования, пока аргументы не будут исчерпаны. Нам нужно отключить использование globbing (подстановочные символы), 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 | xargs -n1 -d: echo
излишним или это не имеет значения?
echo $PATH | xargs -n1 -d:
сделает то же самое для вас, но вы будете использовать еще одну оболочку. Первый из них оценит echo $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
». Скрипт использует оператор подстановки ( 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 -0x3a -l012 -pe '' <<<$PATH
. Объяснение: -0
устанавливает разделитель входной записи (указанный в шестнадцатеричной / восьмеричной нотации, x3A - двоеточие), -l
делает две вещи: 1) разбивает разделитель входной записи, 2) устанавливает разделитель выходной записи, если он указан (в восьмеричной записи) 012 - новая строка). А -p
цикл выводит значение $ _, которая будет каждая линии читать.
-F
информацию. Я использую в -F
сочетании с -an
годами, я никогда не понимал, что одно подразумевает другие. Между прочим, я видел, как Серж упомянул Code Golf , но я думаю, что вам также понравятся Unix и Linux, если вы занимаетесь этим.
-l
также добавляется разделитель выходных записей, который дается в конце каждого вызова печати. Фактически print всегда добавляет разделитель выходной записи $/
к концу строки, если разделитель выходной записи определен. По умолчанию это undef. Так что -l
jus устанавливает $/
, и это заставляет print добавить символ новой строки в конец строки.
Вероятно, единственный способ, который не был упомянут, это то, как я использовал его годами:
echo $PATH | tr ":" "\n"
Итак, в ваш .profile или .bash_profile или что-то еще вы можете добавить:
alias path='echo $PATH | tr ":" "\n"'
Поскольку все языки сценариев уже заняты, я перейду к 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
Но также потому, что «почему бы и нет», вот альтернативная версия Python через аргументы командной строки sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
Ruby не поставляется с Ubuntu по умолчанию, в отличие от компилятора C и интерпретатора Python, но если вы когда-нибудь будете его использовать, решение в Ruby будет таким:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
Как предлагает 7stud (спасибо большое!) В комментариях , это также можно сократить с помощью
ruby -F: -ane 'puts $F' <<<$PATH
и так
ruby -0072 -ne 'puts chomp' <<<$PATH
Мы можем использовать split()
функцию, чтобы разбить строку, считанную в массив, и использовать for-each
цикл, чтобы распечатать каждый элемент на отдельной строке.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
автоматически печатает элементы массива на отдельных строках! Вы также можете сделать так, чтобы переключатели делили: ruby -F: -ane 'puts $F' <<<$PATH
Объяснение: -F
устанавливает $;
указанный символ, который является разделителем по умолчанию, используемым String :: split ($; имеет значение по умолчанию nil, которое разделяется на пробел). -a
вызывает $ _. split, где $ _ - строка, считываемая с использованием gets ()), и присваивает результирующий массив $F
.
-F
флаг - я только начинаю с Руби, поэтому делаю что-то немного грубым.
ruby -0072 -ne 'puts chomp' <<<$PATH
. Объяснение: -0
устанавливает разделитель входной записи (укажите символ в восьмеричном формате; 072 - двоеточие). Ruby использует $ _ аналогично Perl. Метод gets () (используемый в -n
цикле) устанавливает $ _ для текущей строки, которая читается. И chomp()
без аргумента chomps $ _. Мне все еще нравится твой лучше. :)
-F
флагом, короче. Если вы это сделаете, echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
это скажет мне, что это 271 байт, но тот, у которого восьмеричное число равно 276. Это для всей команды, конечно, если мы рассмотрим только код, puts $F
он явно короче. :) Кстати, вы знаете о Code Golf ? Это сайт для решения головоломок с минимальным количеством байтов. Есть вопрос, связанный с этим: codegolf.stackexchange.com/q/96334/55572
Нам нужно больше 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
python3 -c "import os; [print(p) for p in os.getenv('PATH').split(':')]"
Через 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.
echo $PATH | awk '{gsub(/\:/,"\n");print}'
fileinput
когда вы могли бы просто использовать input
:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
Я использую «Функции пути 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'
Расширение параметра оболочки - оно объясняет $ {параметр / шаблон / строку}. Если шаблон начинается с '/', все совпадения шаблона заменяются строкой.
Итак, мы имеем:
Другой способ 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 перестроить запись .
(Это, вероятно, более полезно для случаев, когда для компонентов требуется дополнительная обработка, чем для показанного точного примера простой печати таблицы.)
jq -Rr 'gsub(":";"\n")' <<<$PATH
Как отобразить пути в $ PATH отдельно
Это мои предпочтительные способы сделать это, основываясь на моих соответствующих сценариях использования и заботах о совместимости и использовании ресурсов.
tr
Во-первых, если вам нужно быстрое, легко запоминающееся и читаемое решение, просто введите эхо PATH
и направьте его в translate ( tr
), чтобы превратить двоеточия в новые строки:
echo $PATH | tr : "\n"
Недостатком является использование двух процессов из-за конвейера, но если мы просто взломали терминал, нас это действительно волнует?
Если вам нужно довольно постоянное решение .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* :.
Удачи, помня об этом, когда вы просто взламываете командную строку, если вы еще не добавили псевдоним.
В качестве альтернативы, достаточно кросс-совместимый, читаемый и понятный подход, который не зависит ни от чего, кроме оболочки, использует следующую функцию (я предлагаю в вашей .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.
Это решение проще, чем 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