วิธีแสดงเส้นทางใน $ PATH แยกกัน


44

ฉันไม่สามารถหาวิธีแสดงรายการเส้นทางต่าง ๆ$PATHแยกจากกันเพื่อให้พวกเขามีลักษณะดังนี้:

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

เป็นต้น

ไม่มีใครรู้ว่าตัวแปรที่ถูกต้องสำหรับเรื่องนี้?


แต่ละเส้นทางควรอยู่ในบรรทัดแยกกันโปรด
HankG

สิ่งที่ควรพิมพ์ถ้าเส้นทางของคุณมีการขึ้นบรรทัดใหม่
Martijn


ข้ามไซต์ซ้ำกันunix.stackexchange.com/q/80151/85039
Sergiy Kolodyazhnyy

คำตอบ:


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
Sergiy Kolodyazhnyy

รูปแบบ Python อีกรูปแบบแฮ็ค: python -c "print r'$PATH'.replace(':', '\n')"(ใช้สตริงดิบในกรณีที่แบ็กสแลช)
wjandrea

3
trทำงานได้สำหรับฉัน (บน mac, btw) ขอบคุณ
Mike S.

สำหรับผู้ที่ชอบก็ที่ต้องการที่จะเพิ่มเข้าไปในของพวกเขา.bash_profileเพิ่มมันเช่นนี้alias path='tr ":" "\n" <<< "$PATH"'
ไมค์เอส

63

ใช้การขยายพารามิเตอร์ของ bash :

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

แทนที่ทั้งหมดนี้:ใน$PATHโดยการขึ้นบรรทัดใหม่ ( \n) และพิมพ์ผล เนื้อหาของ$PATHยังคงไม่เปลี่ยนแปลง
หากคุณต้องการแทนที่ครั้งแรก:ให้ลบเครื่องหมายทับที่สอง:echo -e "${PATH/:/\n}"


3
ฉันคิดว่านี่เป็นทางออกที่ดีที่สุดเพราะทำในทุบตีบริสุทธิ์
ryanmjacobs

1
@ryanmjacobs อยากรู้อยากเห็นอย่างอ่อนโยน: สิ่งที่คุณคิดว่าวิธีการแก้ปัญหาของฉันใช้? : D
muru

1
โปรดอธิบายวิธีการใช้งาน
Tulains Córdova

การดำเนินการแบบนั้นเรียกว่าอะไร? มันคล้ายกับ sed แต่ก็ไม่ sed ชื่อของมันคืออะไรดังนั้นฉันสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับเว็บได้
Tulains Córdova

3
ติดตามลิงก์ (การขยายพารามิเตอร์) ในคำตอบของฉันและเลื่อนลงไปที่ส่วนที่สองสุดท้ายที่เรียกว่า:${parameter/pattern/string}
Cyrus

27

ใช้ IFS:

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

IFSถือตัวละครที่ทุบตีไม่แยกดังนั้นIFSด้วย:ทำให้ทุบตีแยกการขยายตัวของบน$PATH วนรอบอาร์กิวเมนต์ของสตริงรูปแบบจนกว่าอาร์กิวเมนต์จะหมดลง เราจำเป็นต้องปิดการใช้งาน globbing (การขยายไวด์การ์ด) โดยใช้เพื่อให้ไวด์การ์ดในชื่อไดเรกทอรี PATH ไม่ได้รับการขยาย:printfset -f


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ซ้ำซ้อนหรือไม่สำคัญ?
Sergiy Kolodyazhnyy

@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และบันทึกผลในอาร์เรย์ The $"เป็นตัวแปร Perl พิเศษคือ "list separator" ซึ่งมีการพิมพ์ค่าระหว่างองค์ประกอบแต่ละรายการของรายการที่พิมพ์ ดังนั้นการตั้งค่าให้ขึ้นบรรทัดใหม่จะทำให้print @listพิมพ์แต่ละองค์ประกอบของ@listและจากนั้นขึ้นบรรทัดใหม่ @Fนี่เรากำลังใช้มันในการพิมพ์

    $ perl -F: -ane 'print join "\n", @F' <<<"$PATH"
    /bin
    usr/bin/
    /usr/local/bin
    /some\ horrible thing
    /even 
    new lines

    ความคิดเช่นเดียวกับข้างต้นเพียงน้อย golfed แทนที่จะใช้$"เรากำลังjoinนำอาร์เรย์ขึ้นบรรทัดใหม่แล้วพิมพ์อย่างชัดเจน

  • เรียบง่ายgrepด้วย PCRE magic:

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

    -oทำให้grepพิมพ์เฉพาะส่วนการจับคู่ของแต่ละบรรทัดเพื่อให้การแข่งขันแต่ละครั้งจะพิมพ์อยู่บนบรรทัดที่แยกต่างหาก -Pช่วยนิพจน์ปกติ Perl เข้ากันได้ (PCRE) regex กำลังค้นหาส่วนขยายของ 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 quotingและเป็นวิธีที่จะพิมพ์ตัวอักษรขึ้นบรรทัดใหม่ในเปลือก

ในตัวอย่างข้างต้นทั้งหมดฉันใช้ตัวดำเนินการstring ( <<<) ของ shell ( ) และ shell อื่น ๆ บางตัว) เพื่อส่งผ่านสตริงเป็นอินพุตไปยังโปรแกรม ดังนั้นจะเทียบเท่ากับcommand <<<"foo" echo -n "foo" | commandโปรดทราบว่าฉันมักจะพูด"$PATH"โดยไม่ต้องพูดราคาเปลือกจะกินตัวละครขึ้นบรรทัดใหม่


@ 7studให้แนวทางอื่นในความคิดเห็นที่ดีเกินไปที่จะไม่รวม:

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

ว่าสิ่งที่เรียกว่าการเล่นกอล์ฟ -0ระบุคั่นบันทึกการป้อนข้อมูลเป็นฐานแปดหรือเลขฐานสิบหกจำนวน นี่คือสิ่งที่กำหนด "บรรทัด" และค่าเริ่มต้นของมันคือ\nอักขระขึ้นบรรทัดใหม่ นี่เรากำลังตั้งไป:ซึ่งเป็นx3aเลขฐานสิบหก (ลองprintf '\x3a\n') -lไม่สามสิ่ง ครั้งแรกก็เอาบันทึกการป้อนข้อมูลแยก ( $/) จากจุดสิ้นสุดของแต่ละสายได้อย่างมีประสิทธิภาพลบ:ที่นี่และครั้งที่สองมันชุดบันทึกเอาท์พุทคั่น ( $\) เพื่อสิ่งที่ฐานแปดหรือค่า hex ก็จะได้รับ ( 012เป็น\n) หาก$\มีการกำหนดจะถูกเพิ่มลงในตอนท้ายของการprintโทรแต่ละครั้งดังนั้นสิ่งนี้จะส่งผลให้มีการขึ้นบรรทัดใหม่ต่อท้ายแต่ละการprintเรียก

-peประสงค์พี rint -eสายการป้อนข้อมูลแต่ละหลังจากการใช้สคริปต์ที่กำหนดโดย ที่นี่ไม่มีสคริปต์เนื่องจากงานทั้งหมดทำโดยตัวเลือกการตั้งค่าสถานะตามที่อธิบายไว้ข้างต้น!


สมุทรของคุณ perl หนึ่งไม่ชัดเจนพอ! ต่อไปนี้เป็นรุ่นที่มีรหัสสำหรับสวิตช์อีในการดำเนินการเพราะสวิทช์อื่น ๆ 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 ตัวอย่างที่ดี
7stud

@ 7stud ว้าวมันช่างยอดเยี่ยมจริงๆขอบคุณ! ถูกขโมยไปอย่างไร้ยางอายและถูกเพิ่มเข้าไปในคำตอบของฉัน (ฉันถือว่าคุณไม่รังเกียจโปรดโพสต์เป็นคำตอบด้วยตัวคุณเองและฉันจะลบทิ้ง) และขอบคุณสำหรับ-Fข้อมูล ฉันใช้-Fร่วมกับ-anมานานหลายปีฉันไม่เคยรู้เลยว่าคนอื่น ๆ อย่างไรก็ตามฉันเห็น Serg พูดถึงCode Golfแต่ฉันคิดว่าคุณจะเพลิดเพลินกับUnix & Linuxเช่นกันหากคุณชอบสิ่งนี้
terdon

เฮ้ขอบคุณ คำชี้แจงอย่างหนึ่งเกี่ยวกับคำสั่งนี้: ในที่สุด-lก็เพิ่มตัวคั่นเร็กคอร์ดเอาท์พุทที่กำหนดไว้ที่ส่วนท้ายของการเรียกใช้การพิมพ์แต่ละครั้ง ในความเป็นจริงการพิมพ์จะเพิ่มตัวคั่นเร็กคอร์ดเอาท์พุทเสมอ$/ไปยังจุดสิ้นสุดของสตริง - หากมีการกำหนดตัวคั่นเร็กคอร์ดเอาท์พุท โดยค่าเริ่มต้นมันเป็น undef ดังนั้น-ljus จึงตั้งค่า$/และทำให้การพิมพ์เพิ่มบรรทัดใหม่ไปยังจุดสิ้นสุดของสตริง
7stud

ฉันคิดว่าคุณไม่รังเกียจ - ไม่เลย :)
7stud

6

ในคำตอบนี้:

  1. C
  2. หลาม
  3. ทับทิม
  4. ทางเลือก awk

1. ค

เนื่องจากภาษาสคริปต์ทั้งหมดได้ถูกใช้ไปแล้วฉันจะไปกับ C. มันค่อนข้างง่ายที่จะรับตัวแปรสภาพแวดล้อมพร้อมget_env()ฟังก์ชั่น (ดูเอกสารประกอบ GNU C Library ) ส่วนที่เหลือเป็นเพียงการจัดการตัวละคร

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 compiler และ Python interpreter แต่ถ้าคุณพบว่าตัวเองกำลังใช้อยู่คำตอบใน 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เรียก _ $. แยกที่ $ _ เป็นสายอ่านในการใช้ที่ได้รับ ()) $Fและกำหนดอาร์เรย์ที่มีผลต่อการ
7 ส.ค.

@ 7stud เฮ้ขอบคุณ! :) ไม่ทราบว่ามี-Fธง - ฉันเพิ่งเริ่มต้นด้วย Ruby ดังนั้นการทำสิ่งที่ค่อนข้างหยาบ
Sergiy Kolodyazhnyy

ไม่นี่เป็นสิ่งที่คลุมเครือ ซับหนึ่งของคุณสามารถอ่านได้มากและความคมชัดควรทรัมป์สั้น ๆ ทุกครั้ง
7

ฮะ ฉันหาคำย่อให้สั้นลง: ruby -0072 -ne 'puts chomp' <<<$PATH. คำอธิบาย: -0ตั้งค่าตัวคั่นเร็กคอร์ดอินพุต (ระบุอักขระในรูปแบบฐานแปด; 072 เป็นโคลอน) Ruby ใช้ $ _ ในรูปแบบที่คล้ายกับ Perl เมธอด gets () (ใช้ใน-nลูป) ตั้งค่า $ _ เป็นบรรทัดปัจจุบันที่อ่านมาและchomp()ไม่มี arg, 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
Sergiy Kolodyazhnyy

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)'

โปรดทราบว่าการเยื้องมีความสำคัญมากในหลาม


Shorter awk:echo $PATH | awk '{gsub(/\:/,"\n");print}'
Sergiy Kolodyazhnyy

ฉันไม่แน่ใจว่าทำไมคุณถึงต้องกังวลfileinputเมื่อคุณสามารถใช้input:python3 -c 'print(*input().split(":"), sep="\n")' <<< "$PATH"
wjandrea

2

ฉันใช้ "Bash Path Function" ของ Stephen Collyer (ดูบทความของเขาใน 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 Quoting - มันอธิบาย $ 'some \ ntext'

การขยายพารามิเตอร์เชลล์ - มันอธิบาย $ {พารามิเตอร์ / รูปแบบ / สตริง}, หากรูปแบบเริ่มต้นด้วย '/' การจับคู่รูปแบบทั้งหมดจะถูกแทนที่ด้วยสตริง

ดังนั้นเราจึงมี:

  1. รูปแบบ/:ซึ่งเริ่มต้นด้วย '/' เพื่อแทนที่การแข่งขันทั้งหมด
  2. สตริง$ '\ n'ซึ่งถูกยกมาด้วยการหดตัว $ 'anytext' เพื่อรักษาสัญลักษณ์บรรทัดใหม่ (\ n)

1

วิธี AWK อีกประการหนึ่งคือการรักษาแต่ละ directory เป็นแยกบันทึกมากกว่าที่จะเป็นแยกฟิลด์

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)เพื่อเปลี่ยน colons ให้เป็นบรรทัดใหม่:

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


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.