Tôi không thể tìm ra cách liệt kê các đường dẫn khác nhau $PATH
một cách riêng biệt để chúng trông như thế này:
/bin
/usr/bin
/usr/local/bin
Vân vân.
Có ai biết biến chính xác cho điều này?
Tôi không thể tìm ra cách liệt kê các đường dẫn khác nhau $PATH
một cách riêng biệt để chúng trông như thế này:
/bin
/usr/bin
/usr/local/bin
Vân vân.
Có ai biết biến chính xác cho điều này?
Câu trả lời:
Hãy thử sed
:
$ sed 's/:/\n/g' <<< "$PATH"
Hoặc tr
:
$ tr ':' '\n' <<< "$PATH"
Hoặc python
:
$ python2 -c "import os; print os.environ['PATH'].replace(':', '\n')"
Ở đây tất cả những điều trên sẽ thay thế tất cả các lần xuất hiện :
bằng các dòng mới \n
.
python -c 'import sys;print sys.argv[1].replace(":","\n")' $PATH
python -c "print r'$PATH'.replace(':', '\n')"
(sử dụng chuỗi thô trong trường hợp dấu gạch chéo ngược)
tr
làm việc cho tôi (trên mac, btw). Cảm ơn.
.bash_profile
, hãy thêm nó như thế này:alias path='tr ":" "\n" <<< "$PATH"'
Sử dụng bash's Parameter Expansion :
echo "${PATH//:/$'\n'}"
Tất cả thay thông số này :
trong $PATH
bởi một dòng mới ( \n
) và in kết quả. Nội dung $PATH
vẫn không thay đổi.
Nếu bạn chỉ muốn thay thế dấu đầu tiên :
, hãy xóa dấu gạch chéo thứ hai:echo -e "${PATH/:/\n}"
${parameter/pattern/string}
Sử dụng IFS:
(set -f; IFS=:; printf "%s\n" $PATH)
IFS
giữ các ký tự trên đó bash không tách, vì vậy một IFS
với :
làm cho bash chia việc mở rộng $PATH
trên :
. printf
lặp các đối số trên chuỗi định dạng cho đến khi hết đối số. Chúng ta cần vô hiệu hóa globalbing (mở rộng ký tự đại diện) bằng cách sử dụng set -f
các ký tự đại diện trong tên thư mục PATH không được mở rộng.
Sử dụng xargs
:
xargs -n1 -d: <<< $PATH
Từ 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
là dư thừa hoặc nó không quan trọng?
echo $PATH | xargs -n1 -d:
sẽ làm điều tương tự cho bạn nhưng bạn sẽ sử dụng thêm một shell. Người đầu tiên sẽ đánh giá echo $PATH
và đầu ra ống cho vỏ tiếp theo để làm phần còn lại.
Đây là tương đương trong 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
Dưới đây là một vài cách tiếp cận. Tôi đang sử dụng một PATH
thư mục chứa dấu gạch chéo ngược, dấu cách và thậm chí một dòng mới để cho thấy rằng chúng nên hoạt động với bất kỳ thứ gì (ngoại trừ dòng cut
bị lỗi trên dòng mới):
$ echo "$PATH"
/bin:usr/bin/:/usr/local/bin:/some\ horrible thing:/even
new lines
Một số cách Perl:
$ perl -pe 's/:/\n/g' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Có -p
nghĩa là "in mọi dòng đầu vào sau khi áp dụng tập lệnh được đưa ra bởi -e
". Kịch bản đang sử dụng toán tử thay thế ( s/oldnew/
) để thay thế tất cả :
bằng các dòng mới.
$ perl -lne 'print for split /:/' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Việc -l
thêm một dòng mới cho mỗi print
cuộc gọi. Ở đây, tập lệnh đang phân tách đầu vào của nó :
và sau đó lặp qua từng phần tử phân tách và in nó.
$ perl -F: -ane '$"="\n";print "@F"' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Việc -a
thực hiện perl
giống như awk
: nó sẽ phân tách từng dòng đầu vào của nó trên ký tự được đưa ra bởi -F
(vì vậy :
, ở đây) và lưu kết quả trong mảng @F
. Các $"
là một biến Perl đặc biệt, "danh sách phân cách", có giá trị được in giữa mỗi phần tử của một danh sách in. Vì vậy, đặt nó thành một dòng mới sẽ làm cho print @list
in từng phần tử @list
và sau đó là một dòng mới. Ở đây, chúng tôi đang sử dụng nó để in @F
.
$ perl -F: -ane 'print join "\n", @F' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Ý tưởng tương tự như trên, chỉ cần ít chơi golf. Thay vì sử dụng $"
, chúng tôi rõ ràng join
ing mảng với dòng mới và sau đó in.
Đơn giản grep
với phép thuật PCRE:
$ grep -oP '(^|:)\K[^:]+' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Các -o
làm cho grep
chỉ in phần gắn kết của mỗi dòng, vì vậy mỗi trận đấu được in trên một dòng riêng biệt. Cho -P
phép biểu thức tương thích thường xuyên tương thích Perl (PCRE). Regex đang tìm kiếm các đoạn không :
( [^:]+
) đi theo đầu dòng ( ^
) hoặc :
ký tự. Đây \K
là một thủ thuật PCRE có nghĩa là "loại bỏ bất cứ thứ gì phù hợp trước thời điểm này" và được sử dụng ở đây để tránh in :
.
Và một cut
giải pháp (điều này không thành công trên các dòng mới, nhưng có thể xử lý dấu gạch chéo ngược và dấu cách):
$ cut -d: -f 1- --output-delimiter=$'\n' <<<"$PATH"
/bin
usr/bin/
/usr/local/bin
/some\ horrible thing
/even
new lines
Các tùy chọn được sử dụng là -d:
đặt dấu phân cách đầu vào :
, -f 1-
có nghĩa là in tất cả các trường (từ đầu đến cuối) và --output-delimiter=$'\n'
thiết lập dấu phân cách đầu ra, tốt, tốt. Đây $'\n'
là trích dẫn ANSI C và là một cách để in một ký tự dòng mới trong trình bao.
Trong tất cả các ví dụ trên, tôi đang sử dụng toán tử bash '(và một số shell khác') ở đây<<<
toán tử chuỗi ( ) để truyền chuỗi dưới dạng đầu vào cho chương trình. Như vậy command <<<"foo"
là tương đương với echo -n "foo" | command
. Lưu ý rằng tôi luôn luôn trích dẫn "$PATH"
, nếu không có dấu ngoặc kép, shell sẽ ăn nhân vật dòng mới.
@ 7stud đã đưa ra một cách tiếp cận khác trong các ý kiến chỉ là quá tốt để không bao gồm:
$ perl -0x3a -l012 -pe '' <<<"$PATH"
Đó là những gì được gọi là golf . Chỉ -0
định dấu phân cách bản ghi đầu vào là số bát phân hoặc thập lục phân. Đây là những gì định nghĩa một "dòng" và giá trị mặc định của nó là \n
, một ký tự dòng mới. Ở đây, chúng ta đang cài đặt nó vào một :
mà là x3a
trong hex (thử printf '\x3a\n'
). Có -l
ba điều. Đầu tiên, nó loại bỏ dấu tách bản ghi đầu vào ( $/
) khỏi cuối mỗi dòng, loại bỏ một cách hiệu quả :
ở đây và thứ hai, nó đặt dấu tách bản ghi đầu ra ( $\
) thành bất kỳ giá trị bát phân hoặc hex nào được đưa ra ( 012
is \n
). Nếu $\
được xác định, nó sẽ được thêm vào cuối mỗi print
cuộc gọi, vì vậy điều này sẽ dẫn đến một dòng mới được thêm vào mỗi cuộc gọi print
.
Ý -pe
chí p rint mỗi dòng đầu vào sau khi áp dụng tập lệnh được đưa ra bởi -e
. Ở đây không có kịch bản vì tất cả công việc được thực hiện bằng các cờ tùy chọn như được mô tả ở trên!
perl -0x3a -l012 -pe '' <<<$PATH
. Giải thích: -0
đặt dấu tách bản ghi đầu vào (được chỉ định trong ký hiệu hex / bát phân, x3A là dấu hai chấm), -l
thực hiện hai điều: 1) nó phân tách dấu tách bản ghi đầu vào, 2) nó đặt dấu tách bản ghi đầu ra nếu được chỉ định (theo ký hiệu bát phân , 012 là một dòng mới). Một -p
vòng lặp in ra giá trị của $ _, sẽ là mỗi dòng được đọc.
-F
thông tin. Tôi đã sử dụng -F
kết hợp với -an
nhiều năm, tôi chưa bao giờ nhận ra cái này ngụ ý những cái khác. Nhân tiện, tôi thấy Serg đã đề cập đến Code Golf , nhưng tôi nghĩ bạn cũng sẽ thích Unix & Linux nếu bạn thích loại này.
-l
cũng thêm dấu phân tách bản ghi đầu ra được cung cấp vào cuối mỗi lệnh gọi in. Trong thực tế, in luôn thêm dấu tách bản ghi đầu ra $/
, vào cuối chuỗi - nếu phân tách bản ghi đầu ra được xác định. Theo mặc định, nó là undef. Vì vậy, -l
jus đặt $/
và điều đó khiến cho việc in thêm dòng mới vào cuối chuỗi.
Vì tất cả các ngôn ngữ kịch bản đã được sử dụng, tôi sẽ sử dụng C. Việc lấy các biến môi trường có get_env()
chức năng khá dễ dàng (xem tài liệu Thư viện GNU C ). Phần còn lại chỉ đơn giản là thao tác nhân vật
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
Nhưng cũng bởi vì "tại sao không", đây là phiên bản python thay thế thông qua các đối số dòng lệnh sys.argv
python -c 'import sys; print "\n".join(sys.argv[1].split(":"))' "$PATH"
Ruby không đi kèm với Ubuntu theo mặc định, không giống như trình biên dịch C và trình thông dịch Python, nhưng nếu bạn thấy mình sử dụng nó, giải pháp trong Ruby sẽ là:
ruby -ne 'puts $_.split(":")' <<< "$PATH"
Theo đề xuất của 7stud (Cảm ơn bạn rất nhiều!) Trong các bình luận , điều này cũng có thể được rút ngắn với
ruby -F: -ane 'puts $F' <<<$PATH
và cách này
ruby -0072 -ne 'puts chomp' <<<$PATH
Chúng ta có thể sử dụng split()
chức năng để chia dòng đọc thành mảng và sử dụng for-each
vòng lặp để in ra từng mục trên dòng riêng biệt.
awk '{split($0,arr,":"); for(var in arr) print arr[var]}' <<< $PATH
puts
tự động in các phần tử của một mảng trên các dòng riêng biệt! Bạn cũng có thể làm cho các công tắc thực hiện phân tách: ruby -F: -ane 'puts $F' <<<$PATH
Giải thích: -F
đặt $;
thành ký tự được chỉ định, là dấu tách mặc định được sử dụng bởi String :: split ($; có giá trị mặc định là nil, phân tách trên khoảng trắng). -a
gọi $ _. split, trong đó $ _ là một dòng được đọc bằng cách sử dụng got ()) và gán mảng kết quả cho $F
.
-F
cờ - Tôi mới bắt đầu với Ruby, nên làm mọi thứ hơi thô thiển.
ruby -0072 -ne 'puts chomp' <<<$PATH
. Giải thích: -0
đặt dấu tách bản ghi đầu vào (chỉ định một ký tự ở định dạng bát phân; 072 là dấu hai chấm). Ruby sử dụng $ _ theo cách tương tự như Perl. Phương pháp được () (được sử dụng trong -n
vòng lặp) bộ $ _ với dòng dòng đó của đọc. Và chomp()
không có arg, chomps $ _. Tôi vẫn thích bạn tốt hơn. :)
-F
cờ, ngắn hơn. Nếu bạn làm điều echo "ruby -F: -ane 'puts $F' <<<$PATH" |wc -c
đó cho tôi biết đó là 271, byte, nhưng cái có số bát phân là 276. Tất nhiên, đó là cho toàn bộ lệnh, nếu chúng ta chỉ xem xét bản thân mã puts $F
thì ngắn hơn rõ ràng. :) Nhân tiện, bạn có biết về Code Golf không? Đây là trang web cho các giải pháp để lập trình các câu đố với số byte ngắn nhất. Có một câu hỏi liên quan đến câu hỏi này: codegolf.stackexchange.com/q/96334/55572
Có lẽ cách duy nhất chưa được đề cập là cách tôi đã sử dụng nó trong nhiều năm:
echo $PATH | tr ":" "\n"
vì vậy, trong .profile hoặc .bash_profile của bạn hoặc bất cứ điều gì, bạn có thể thêm:
alias path='echo $PATH | tr ":" "\n"'
Chúng ta cần thêm Java!
public class GetPathByLine {
public static void main(String[] args) {
for (String p : System.getenv("PATH").split(":")) {
System.out.println(p);
}
}
}
Lưu cái này vào GetPathByLine.java
và biên dịch bằng cách sử dụng:
javac GetPathByLine.java
Chạy với:
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(':')]"
Qua awk.
echo $PATH | awk -F: '{for(i=1;i<=NF;i++)print $i}'
Qua trăn.
$ echo $PATH | python3 -c 'import fileinput
for line in fileinput.input():
for i in line.split(":"):
print(i)'
Lưu ý rằng thụt là rất quan trọng trong python.
echo $PATH | awk '{gsub(/\:/,"\n");print}'
fileinput
khi bạn chỉ có thể sử dụng input
:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
Tôi sử dụng "Bash Path Function" của Stephen Colly (xem bài viết của ông trên Tạp chí Linux ). Nó cho phép tôi sử dụng "danh sách phân tách dấu hai chấm" làm kiểu dữ liệu trong lập trình shell. Ví dụ: tôi có thể tạo một danh sách tất cả các thư mục trong thư mục hiện tại bằng cách:
dirs="";for i in * ; do if [ -d $i ] ; then addpath -p dirs $i; fi; done
Sau đó, listpath -p dirs
tạo ra một danh sách.
Giải thích cho câu trả lời @Cyrus
echo "${PATH//:/$'\n'}"
Ghi chú:
Trích dẫn ANSI-C - nó giải thích $ 'some \ ntext'
Mở rộng tham số Shell - nó giải thích $ {tham số / mẫu / chuỗi}, Nếu mẫu bắt đầu bằng '/', tất cả các kết quả khớp của mẫu được thay thế bằng chuỗi.
Vì vậy chúng tôi có:
Một cách khác của AWK là coi mỗi thư mục là một bản ghi riêng , thay vì một trường riêng biệt .
awk 'BEGIN{RS=":"} {print $0}' <<<"$PATH"
Tôi thấy cú pháp đó đặc biệt trực quan. Nhưng, nếu bạn thích, bạn có thể rút ngắn nó bằng cách làm print $0
ẩn (đó là hành động mặc định và 1
đánh giá là đúng, khiến nó được thực hiện cho mọi dòng):
awk 'BEGIN{RS=":"} 1' <<<"$PATH"
Dấu tách bản ghi đầu vào và đầu ra mặc định của AWK là dòng mới (ngắt dòng). Bằng cách đặt dấu tách bản ghi đầu vào ( RS
) thành :
trước khi đọc đầu vào, AWK sẽ tự động phân tích cú pháp dấu hai chấm được phân định $PATH
thành các tên thư mục cấu thành của nó. AWK mở rộng $0
đến từng bản ghi, dòng mới vẫn là dấu phân tách bản ghi đầu ra và không cần lặp hoặc gsub
cần thiết.
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 thường được sử dụng để phân tích các bản ghi thành các trường riêng biệt, nhưng không cần điều đó chỉ để xây dựng một danh sách các tên thư mục.
Điều này hoạt động ngay cả đối với đầu vào có khoảng trống (khoảng trắng và tab), thậm chí nhiều khoảng trống liên tiếp:
ek@Io:~$ awk 'BEGIN{RS=":"} {print $0}' <<<$'ab\t\t c:de fg:h'
ab c
de fg
h
Đó là, trừ khi bạn khiến AWK xây dựng lại bản ghi (xem bên dưới), không có vấn đề gì để có khoảng trắng hoặc tab (dấu phân cách trường mặc định) trong đầu vào. Bạn PATH
có lẽ không chứa khoảng trắng trên một hệ thống Ubuntu, nhưng nếu có, đây vẫn sẽ làm việc.
Điều đáng nói, như một lưu ý phụ, rằng khả năng diễn giải bản ghi của AWK là một tập hợp các trường trở nên hữu ích cho vấn đề liên quan đến việc xây dựng bảng các thành phần thư mục :
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
Nhiệm vụ gây tò mò phục vụ mục đích buộc AWK phải xây dựng lại hồ sơ .
(Điều này có lẽ hữu ích hơn cho các trường hợp xử lý bổ sung được thực hiện trên các thành phần, so với ví dụ chính xác được hiển thị chỉ đơn giản là in bảng.)
jq -Rr 'gsub(":";"\n")' <<<$PATH
Cách hiển thị các đường dẫn trong $ PATH riêng
Đây là những cách ưa thích của tôi để làm điều này dựa trên các trường hợp sử dụng tương ứng và mối quan tâm của tôi về khả năng tương thích và sử dụng tài nguyên.
tr
Đầu tiên, nếu bạn cần một giải pháp nhanh chóng, dễ nhớ và dễ đọc, chỉ cần lặp lại PATH
và chuyển nó sang dịch ( tr
) để biến dấu hai chấm thành dòng mới:
echo $PATH | tr : "\n"
Nó có nhược điểm của việc sử dụng hai quy trình vì đường ống, nhưng nếu chúng ta chỉ hack trong một thiết bị đầu cuối, chúng ta có thực sự quan tâm đến điều đó không?
Nếu bạn muốn một giải pháp khá lâu dài trong .bashrc
sử dụng tương tác của mình , bạn có thể đặt bí danh cho lệnh sau path
, nhưng khả năng đọc của giải pháp này là đáng nghi ngờ:
alias path="echo \"${PATH//:/$'\n'}\""
Nếu mẫu bắt đầu bằng '/', tất cả các kết quả khớp của mẫu được thay thế bằng chuỗi. Thông thường chỉ có trận đấu đầu tiên được thay thế.
Lệnh trên thay thế dấu hai chấm bằng dòng mới bằng cách sử dụng Mở rộng tham số Shell của Bash :
${parameter/pattern/string}
Để giải thích nó:
# v--v---------delimiters, a'la sed
echo "${PATH//:/$'\n'}"
# ^^ ^^^^^----string, $ required to get newline character.
# \----------pattern, / required to substitute for *every* :.
Chúc may mắn nhớ điều này khi bạn chỉ hack trên dòng lệnh, mặc dù bạn không có bí danh.
Ngoài ra, một cách tiếp cận tương thích chéo, dễ đọc và dễ hiểu mà không dựa vào bất cứ thứ gì ngoài vỏ được sử dụng chức năng sau (tôi đề nghị trong của bạn .bashrc
.)
Hàm sau tạm thời biến Dấu tách trường nội bộ (hoặc Đầu vào) (IFS) thành dấu hai chấm và khi một mảng được đưa vào printf
, nó sẽ thực thi cho đến khi mảng được sử dụng hết:
path () {
local IFS=:
printf "%s\n" ${PATH}
}
Phương pháp này tạo ra chức năng , IFS
và printf
được quy định của posix, vì vậy nó sẽ làm việc trong hầu hết các posix giống như vỏ (đặc biệt là Dash, mà Ubuntu thường bí danh như sh
).
Bạn có nên sử dụng Python cho việc này? Bạn có thể. Đây là lệnh Python ngắn nhất tôi có thể nghĩ ra cho việc này:
python -c "print('\n'.join('${PATH}'.split(':')))"
hoặc chỉ Python 3 (và có lẽ dễ đọc hơn?):
python3 -c "print(*'${PATH}'.split(':'), sep='\n')"
Chúng cũng hoạt động trong mọi môi trường shell thông thường, miễn là bạn có Python.
Giải pháp này đơn giản hơn các giải pháp Java , C , go và awk :
$ LPATH=$PATH wine cmd /c echo %LPATH::=$'\n'% 2> /dev/null
/usr/local/bin
/usr/local/sbin
/usr/bin
/usr/sbin
Đây là một khả năng tuyệt vời khác:
$ 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
Điều này sẽ yêu cầu một số phụ thuộc được cài đặt:
sudo apt-get install openjdk-8-jdk-headless bsh