การขยายตัวเชลล์ (A | B) ในชื่อไฟล์?


9

เป็นไปได้หรือไม่ที่จะขยายorทางเลือกในเชลล์เมื่ออ่านไฟล์ตัวอย่าง

สิ่งที่ฉันหมายถึงคือการgrepสนับสนุนไวยากรณ์ที่ต้องการ(A|B)จับคู่ A หรือ B ในไฟล์

ในทำนองเดียวกันถ้าฉันมีไฟล์เหล่านี้:

file1.txt
file2.txt
file3.txt
file4.txt
file5.txt

ฉันทำได้cat file{1..5}.txtในbashขณะที่มันขยายช่วง มีวิธีที่เท่าเทียมกันในการทำเช่นนี้เพียงไม่กี่ไฟล์?

เช่นcat file(1|5).txtและพิมพ์ 2 เหล่านั้นเท่านั้น

คำตอบ:


16

รูปแบบชื่อแฟ้ม globbing มาตรฐานเพื่อให้ตรงกับหลัก[0-9]คือ ตรงกับหลักเดียว:

cat file[0-9].txt

ในการเลือกเพียงสองข้อต่อไปนี้:

cat file[25].txt

สำหรับตัวเลขที่มีขนาดใหญ่กว่า 9 การขยายรั้งจะมีประโยชน์ (แต่ดูหมายเหตุด้านล่างสำหรับความแตกต่างระหว่างรูปแบบการวนรอบและการขยายรั้ง):

cat file{25..60}.txt

อีกครั้งการขยายรั้งช่วยให้ตัวเลขแต่ละตัวเช่นกัน:

cat file{12,45,900,xyz}.txt

(โปรดทราบว่าในตัวอย่างข้างต้นการขยายรั้งไม่เกี่ยวข้องกับการวนรอบทางคณิตศาสตร์ แต่เพียงสร้างชื่อตามสตริงที่ให้ไว้)

ในbashเมื่อextglobเปิดใช้งานตัวเลือกเชลล์ ( shopt -s extglob) ตัวเลือกต่อไปนี้จะใช้งานได้:

cat file@(12|45|490|foo).txt

@(...)รูปแบบจะตรงกับหนึ่งรวมใด ๆ|รูปแบบ -delimited


ความแตกต่างระหว่างรูปแบบการวนเป็น[...]และ@(...)และการขยายรั้งคือว่าการขยายรั้งถูกสร้างขึ้นในบรรทัดคำสั่งและอาจไม่ตรงกับชื่อที่มีอยู่ในไดเรกทอรีปัจจุบัน รูปแบบชื่อไฟล์ globbing จะตรงกับชื่อ แต่เชลล์จะไม่บ่นหากไม่มีชื่อที่เป็นไปได้ทั้งหมด หากไม่มีชื่อที่ตรงกันรูปแบบจะยังคงไม่ขยายออกเว้นแต่ว่าจะมีการnullglobตั้งค่าตัวเลือกของเชลล์ซึ่งในกรณีนี้รูปแบบจะถูกลบออก

ตัวอย่าง:

touch file1

ls file[0-9]

ที่นี่เฉพาะรายชื่อไฟล์ที่file1จะแสดง

ด้วยls file{0..9}, lsจะบ่นเกี่ยวกับการไม่ได้หาfile0, file2ฯลฯ

ในตัวอย่างต่อไปนี้คำสั่งแรกจะสัมผัสเฉพาะชื่อที่มีอยู่ที่ตรงกับรูปแบบที่กำหนดในขณะที่บรรทัดที่สองจะสร้างไฟล์ที่ไม่มีอยู่:

touch file[0-9]

touch file{0..9}

@thecarpy ฉันขอโทษ file45.txtแต่ที่ไม่ได้รูปแบบที่จะตรงเช่น การแสดงออกวงเล็บจะ[...]ทำงานเช่นเดียวกับการแสดงออกปกติ แต่ใช้!แทน^การพูดว่า "ไม่ได้อยู่ใน" [...]รูปแบบที่มักจะตรงกับตัวอักษรตัวเดียว
Kusalananda

คุณพูดถูก! BTW ฉัน{1,2}ไม่ได้เป็น POSIX อย่างใดอย่างหนึ่ง ... ได้เรียนรู้สิ่งใหม่วันนี้!
thecarpy

2
ความจริงที่ว่าการขยายรั้งไม่จำเป็นต้องตรงกับไฟล์จริงอาจมีประโยชน์อย่างยิ่งหากคุณใช้มันเพื่อสร้างรูปแบบที่จะส่งผ่านgrepสร้าง URL ที่จะส่งต่อcurlและอื่น ๆ ... แต่มันอาจทำให้สับสน สำหรับคนที่คุ้นเคยกับการทำงานกับ globs
เควิน

@ เควินถูกต้อง การขยายรั้งไม่จำเป็นต้องเกี่ยวกับชื่อไฟล์
Kusalananda

7

ไวยากรณ์การใช้งานfile{1,2}ซึ่งจะประเมินและfile1file2

$ ls
$ touch file{1,2,3,4,5,6,7,8,9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

ดังที่ Inian ชี้ให้เห็นด้านล่างเช่นกัน ... มันจะง่ายกว่าที่จะทำtouch file{1..9}ในกรณีตัวอย่างนี้ ...

$ ls
$ touch file{1..9}
$ ls
file1  file2  file3  file4  file5  file6  file7  file8  file9

คุณยังสามารถใช้หลายนิพจน์เช่น:

$ ls
$ touch file{1..9}{a..z}
$ ls
file1a file1b file1c
[...]
file9x file9y file9z

ใช่ข้างต้นจะสร้างไฟล์234 ( 9เท่า26)


1
นี้file{1,2} ไวยากรณ์ยังสะดวกในการเปลี่ยนชื่อไฟล์:mv some_very_long_filename.txt{,.bak}
เอริค DUMINIL

6

ใช่คุณสามารถใช้การขยายรั้งในbashเปลือก สำหรับไฟล์ที่ทำfile{1..2}หรือเพียงแค่สองสามไฟล์file{1,2}

หรือหากคุณกังวลเกี่ยวกับไฟล์ที่ไม่ได้อยู่ในบางกรณีให้ทำการวนซ้ำแบบง่ายๆ

for file in file{1..4}.txt; do
    [ -f "$file" ] || continue
    echo "$file" # Do other actions on file here
done

หรือถ้าเพียงแค่การต่อข้อมูลเป็นการดำเนินการเพียงอย่างเดียวของคุณกับไฟล์และหากคุณไม่แน่ใจว่าไฟล์ใดที่ไม่สามารถแสดงได้ ณ เวลาใดเวลาเพียงแค่catพวกเขาและระงับข้อผิดพลาด การนำข้อผิดพลาดมาตรฐานอีกครั้งเพื่อ/dev/nullระงับข้อผิดพลาดหากไฟล์ไม่พร้อมใช้งาน

cat file{1,5}.txt 2>/dev/null

หรือใช้การแสดงออก glob file[15]ซึ่งไม่บ่นเกี่ยวกับข้อผิดพลาดหากไม่พบไฟล์

cat file[15].txt

2
ไม่, ไม่ต้องกังวลเกี่ยวกับไฟล์ที่ไม่ได้อยู่ที่นั่น, ฉันแค่ต้องการแสดงเนื้อหาของ 2 ไฟล์ที่มีตัวเลขเป็นตัวเลข, แต่นั่นไม่ได้ต่อเนื่องกันดังนั้นfile{1,5}ไวยากรณ์คอมม่าคือทั้งหมดที่ฉันหายไป!
Joe Healey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.