Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม BASH

วิธีตั้งโปรแกรมด้วย Bash:ตัวดำเนินการเชิงตรรกะและการขยายเชลล์

Bash เป็นภาษาการเขียนโปรแกรมที่ทรงพลัง ซึ่งออกแบบมาอย่างสมบูรณ์แบบสำหรับใช้กับบรรทัดคำสั่งและในเชลล์สคริปต์ ซีรีส์สามส่วนนี้ (ซึ่งอิงตามหลักสูตรการศึกษาด้วยตนเองของ Linux สามเล่มของฉัน) สำรวจโดยใช้ Bash เป็นภาษาการเขียนโปรแกรมบนอินเทอร์เฟซบรรทัดคำสั่ง (CLI)

บทความแรกสำรวจการเขียนโปรแกรมบรรทัดคำสั่งง่ายๆ ด้วย Bash รวมถึงการใช้ตัวแปรและตัวดำเนินการควบคุม บทความที่สองนี้จะกล่าวถึงประเภทของตัวดำเนินการเชิงตรรกะของไฟล์ สตริง ตัวเลข และตรรกะอื่นๆ ที่ให้ตรรกะการควบคุมโฟลว์การดำเนินการและส่วนขยายเชลล์ประเภทต่างๆ ใน ​​Bash บทความที่สามและเป็นบทความสุดท้ายในซีรีส์นี้จะสำรวจ สำหรับ , ในขณะที่ และ จนถึง ลูปที่เปิดใช้งานการทำงานซ้ำๆ

ตัวดำเนินการเชิงตรรกะเป็นพื้นฐานสำหรับการตัดสินใจในโปรแกรมและดำเนินการชุดคำสั่งต่างๆ ตามการตัดสินใจเหล่านั้น ซึ่งบางครั้งเรียกว่าการควบคุมการไหล

ตัวดำเนินการตรรกะ

Bash มีชุดตัวดำเนินการเชิงตรรกะจำนวนมากที่สามารถใช้ในนิพจน์เงื่อนไขได้ รูปแบบพื้นฐานที่สุดของ ถ้า โครงสร้างการควบคุมทดสอบเงื่อนไขแล้วรันรายการคำสั่งโปรแกรมหากเงื่อนไขเป็นจริง โอเปอเรเตอร์มีสามประเภท:ตัวดำเนินการไฟล์ ตัวเลข และตัวดำเนินการที่ไม่ใช่ตัวเลข โอเปอเรเตอร์แต่ละตัวจะส่งกลับค่า true (0) หากตรงตามเงื่อนไขและเป็นเท็จ (1) หากไม่ตรงตามเงื่อนไข

ไวยากรณ์การทำงานของตัวดำเนินการเปรียบเทียบเหล่านี้เป็นอาร์กิวเมนต์หนึ่งหรือสองอาร์กิวเมนต์ที่มีตัวดำเนินการอยู่ในวงเล็บปีกกา ตามด้วยรายการคำสั่งโปรแกรมที่ดำเนินการหากเงื่อนไขเป็นจริง และรายการตัวเลือกของคำสั่งโปรแกรมหากเงื่อนไขเป็นเท็จ :

if [ ตัวดำเนินการ arg1 arg2 ]; จากนั้นแสดงรายการ
หรือ
ถ้า [ ตัวดำเนินการ arg1 arg2 ]; แล้วรายการ; รายการอื่น; fi

ช่องว่างในการเปรียบเทียบจำเป็นต้องใช้ตามที่แสดง วงเล็บเหลี่ยมเดี่ยว [ และ ] เป็นสัญลักษณ์ทุบตีแบบดั้งเดิมที่เทียบเท่ากับ การทดสอบ คำสั่ง:

if test arg1 operator arg2 ; then list 

นอกจากนี้ยังมีรูปแบบที่ใหม่กว่าซึ่งมีข้อดีบางประการและผู้ดูแลระบบบางคนต้องการ รูปแบบนี้เข้ากันได้น้อยกว่าเล็กน้อยกับ Bash เวอร์ชันต่างๆ และเชลล์อื่นๆ เช่น ksh ( Korn เชลล์) ดูเหมือนว่า:

if [[ arg1 operator arg2 ]] ; then list 

ตัวดำเนินการไฟล์

ตัวดำเนินการไฟล์คือชุดตัวดำเนินการเชิงตรรกะที่มีประสิทธิภาพภายใน Bash รูปที่ 1 แสดงตัวดำเนินการต่างๆ มากกว่า 20 ตัวที่ Bash สามารถดำเนินการกับไฟล์ได้ ฉันใช้มันค่อนข้างบ่อยในสคริปต์ของฉัน

ตัวดำเนินการ คำอธิบาย
-a ชื่อไฟล์ จริงถ้ามีไฟล์อยู่; อาจว่างเปล่าหรือมีเนื้อหาบางอย่าง แต่ตราบใดที่ยังมีอยู่ สิ่งนี้จะเป็นจริง
-b ชื่อไฟล์ จริงถ้ามีไฟล์อยู่และเป็นไฟล์บล็อกพิเศษ เช่น ฮาร์ดไดรฟ์อย่าง /dev/sda หรือ /dev/sda1
-c ชื่อไฟล์ จริงถ้ามีไฟล์อยู่และเป็นไฟล์อักขระพิเศษ เช่น อุปกรณ์ TTY เช่น /dev/TTY1
-d ชื่อไฟล์ จริงถ้าไฟล์นั้นมีอยู่และเป็นไดเร็กทอรี
-e ชื่อไฟล์ จริงถ้ามีไฟล์อยู่; นี้เหมือนกับ -a ด้านบน
-f ชื่อไฟล์ จริงถ้าไฟล์นั้นมีอยู่และเป็นไฟล์ปกติ ซึ่งต่างจากไดเร็กทอรี ไฟล์พิเศษของอุปกรณ์ หรือลิงก์ เป็นต้น
-g ชื่อไฟล์ จริงถ้ามีไฟล์อยู่และเป็น set-group-id , SETGID
-h ชื่อไฟล์ จริงถ้าไฟล์นั้นมีอยู่และเป็นลิงค์สัญลักษณ์
-k ชื่อไฟล์ จริงถ้ามีไฟล์อยู่และมีการตั้งค่าบิต "เหนียว" ไว้
-p ชื่อไฟล์ จริงถ้าไฟล์นั้นมีอยู่และเป็นไปป์ที่มีชื่อ (FIFO)
-r ชื่อไฟล์ จริงหากไฟล์นั้นมีอยู่และสามารถอ่านได้ กล่าวคือ มีชุดบิตสำหรับอ่านอยู่
-s ชื่อไฟล์ จริงถ้าไฟล์นั้นมีอยู่และมีขนาดที่มากกว่าศูนย์ ไฟล์ที่มีอยู่แต่มีขนาดศูนย์จะคืนค่าเท็จ
-t fd จริงถ้าตัวอธิบายไฟล์ fd เปิดอยู่และหมายถึงเทอร์มินัล
-u ชื่อไฟล์ จริงถ้ามีไฟล์และ set-user-id บิตถูกตั้งค่า
-w ชื่อไฟล์ จริงถ้าไฟล์นั้นมีอยู่และสามารถเขียนได้
-x ชื่อไฟล์ True ถ้าไฟล์นั้นมีอยู่และสามารถเรียกใช้งานได้
-G ชื่อไฟล์ จริงถ้ามีไฟล์และเป็นเจ้าของโดย ID กลุ่มที่มีผลบังคับ
-L ชื่อไฟล์ จริงถ้าไฟล์นั้นมีอยู่และเป็นลิงค์สัญลักษณ์
-N ชื่อไฟล์ จริงถ้ามีไฟล์อยู่และได้รับการแก้ไขตั้งแต่อ่านครั้งสุดท้าย
-O ชื่อไฟล์ จริงถ้ามีไฟล์และเป็นเจ้าของโดย ID ผู้ใช้ที่มีประสิทธิภาพ
-S ชื่อไฟล์ จริงถ้าไฟล์นั้นมีอยู่และเป็นซ็อกเก็ต
file1 -ef file2 จริงถ้า file1 และ file2 หมายถึงอุปกรณ์และหมายเลข iNode เดียวกัน
file1 -nt file2 จริงถ้า file1 ใหม่กว่า (ตามวันที่แก้ไข) กว่า file2 หรือถ้า file1 มีอยู่แล้วและ file2 ไม่มี
file1 -ot file2 จริงถ้า file1 เก่ากว่า file2 หรือถ้า file2 มีอยู่แล้วและ file1 ไม่มี

รูปที่ 1:ตัวดำเนินการไฟล์ Bash

ตัวอย่างเช่น เริ่มต้นด้วยการทดสอบการมีอยู่ของไฟล์:

[student@studentvm1 testdir]$ File="TestFile1"; ถ้า [ -e $File ]; จากนั้น echo "ไฟล์ $File มีอยู่"; อื่น echo "ไฟล์ $File ไม่มีอยู่"; fi
ไม่มีไฟล์ TestFile1
[student@studentvm1 testdir]$

ถัดไป สร้างไฟล์สำหรับการทดสอบชื่อ TestFile1 . สำหรับตอนนี้ ไม่จำเป็นต้องมีข้อมูลใดๆ:

[student@studentvm1 testdir]$ touch TestFile1 

ง่ายต่อการเปลี่ยนค่าของ $File ตัวแปรแทนที่จะเป็นสตริงข้อความสำหรับชื่อไฟล์ในหลายตำแหน่งในโปรแกรม CLI แบบสั้นนี้:

[student@studentvm1 testdir]$ File="TestFile1"; ถ้า [ -e $File ]; จากนั้น echo "ไฟล์ $File มีอยู่"; อื่น echo "ไฟล์ $File ไม่มีอยู่"; fi
มีไฟล์ TestFile1 อยู่
[student@studentvm1 testdir]$

ตอนนี้ ทำการทดสอบเพื่อดูว่ามีไฟล์อยู่หรือไม่และมีความยาวไม่เป็นศูนย์ ซึ่งหมายความว่ามีข้อมูลอยู่ คุณต้องการทดสอบเงื่อนไขสามประการ:1. ไฟล์ไม่มีอยู่; 2. ไฟล์มีอยู่และว่างเปล่า และ 3. ไฟล์นั้นมีอยู่และมีข้อมูลอยู่ ดังนั้น คุณต้องมีชุดการทดสอบที่ซับซ้อนกว่านี้ ใช้ elif บทใน if-elif-else สร้างเพื่อทดสอบเงื่อนไขทั้งหมด:

[student@studentvm1 testdir]$ File="TestFile1"; ถ้า [ -s $File ]; จากนั้น echo "$File มีอยู่และมีข้อมูลอยู่"; fi
[student@studentvm1 testdir]$

ในกรณีนี้ ไฟล์นั้นมีอยู่แต่ไม่มีข้อมูลใดๆ เพิ่มข้อมูลแล้วลองอีกครั้ง:

[student@studentvm1 testdir]$ File="TestFile1"; echo "นี่คือไฟล์ $File"> $File; ถ้า [ -s $File ]; จากนั้น echo "$File มีอยู่และมีข้อมูลอยู่"; fi
TestFile1 มีอยู่และมีข้อมูลอยู่
[student@studentvm1 testdir]$

ใช้งานได้ แต่มันแม่นยำจริง ๆ สำหรับเงื่อนไขใดเงื่อนไขหนึ่งจากสามเงื่อนไขที่เป็นไปได้ เพิ่ม อื่นๆ stanza เพื่อให้คุณค่อนข้างแม่นยำยิ่งขึ้น และลบไฟล์เพื่อให้คุณสามารถทดสอบโค้ดใหม่นี้ได้อย่างเต็มที่:

[student@studentvm1 testdir]$ File="TestFile1"; rm $ไฟล์; ถ้า [ -s $File ]; จากนั้น echo "$File มีอยู่และมีข้อมูลอยู่"; อื่น echo "$ ไฟล์ไม่มีอยู่หรือว่างเปล่า"; fi
TestFile1 ไม่มีอยู่หรือว่างเปล่า

ตอนนี้สร้างไฟล์เปล่าเพื่อทดสอบ:

[student@studentvm1 testdir]$ File="TestFile1"; แตะ $File; ถ้า [ -s $File ]; จากนั้น echo "$File มีอยู่และมีข้อมูลอยู่"; อื่น echo "$ ไฟล์ไม่มีอยู่หรือว่างเปล่า"; fi
TestFile1 ไม่มีอยู่หรือว่างเปล่า

เพิ่มเนื้อหาลงในไฟล์แล้วทดสอบอีกครั้ง:

[student@studentvm1 testdir]$ File="TestFile1"; echo "นี่คือไฟล์ $File"> $File; ถ้า [ -s $File ]; จากนั้น echo "$File มีอยู่และมีข้อมูลอยู่"; อื่น echo "$ ไฟล์ไม่มีอยู่หรือว่างเปล่า"; fi
TestFile1 มีอยู่และมีข้อมูลอยู่

ตอนนี้ เพิ่ม เอลฟ์ stanza เพื่อแยกแยะระหว่างไฟล์ที่ไม่มีอยู่และไฟล์ที่ว่างเปล่า:

[student@studentvm1 testdir]$ File="TestFile1"; แตะ $File; ถ้า [ -s $File ]; จากนั้น echo "$File มีอยู่และมีข้อมูลอยู่"; elif [ -e $File ]; จากนั้น echo "$ ไฟล์มีอยู่และว่างเปล่า"; อื่น echo "$ ไฟล์ไม่มีอยู่"; fi
TestFile1 มีอยู่และว่างเปล่า
[student@studentvm1 testdir]$ File="TestFile1"; echo "นี่คือ $File"> $File; ถ้า [ -s $File ]; จากนั้น echo "$File มีอยู่และมีข้อมูลอยู่"; elif [ -e $File ]; จากนั้น echo "$ ไฟล์มีอยู่และว่างเปล่า"; อื่น echo "$ ไฟล์ไม่มีอยู่"; fi
TestFile1 มีอยู่และมีข้อมูลอยู่
[student@studentvm1 testdir]$

ตอนนี้คุณมีโปรแกรม Bash CLI ที่สามารถทดสอบเงื่อนไขที่แตกต่างกันทั้งสามนี้… แต่ความเป็นไปได้นั้นไม่มีที่สิ้นสุด

จะง่ายกว่าที่จะเห็นโครงสร้างลอจิกของคำสั่งผสมที่ซับซ้อนมากขึ้น ถ้าคุณจัดเรียงคำสั่งโปรแกรมเหมือนกับที่คุณทำในสคริปต์ที่คุณสามารถบันทึกในไฟล์ได้ รูปที่ 2 แสดงให้เห็นว่าสิ่งนี้จะมีลักษณะอย่างไร การเยื้องของคำสั่งโปรแกรมในแต่ละบทของ if-elif-else โครงสร้างช่วยชี้แจงตรรกะ

File="TestFile1"
echo "This is $File"> $File
if [ -s $File ]
   แล้ว
   echo "$File มีอยู่แล้วและมีข้อมูล ."
elif [ -e $File ]
   จากนั้น
   echo "$File มีและว่างเปล่า"
else
   echo "$File ไม่มีอยู่"
fi

รูปที่ 2:โปรแกรมบรรทัดคำสั่งเขียนใหม่ตามที่ปรากฏในสคริปต์

ตรรกะที่ซับซ้อนนี้ยาวเกินไปสำหรับโปรแกรม CLI ส่วนใหญ่ แม้ว่าคำสั่งในตัวของ Linux หรือ Bash อาจใช้ในโปรแกรม CLI ได้ เนื่องจากโปรแกรม CLI นั้นยาวและซับซ้อนมากขึ้น การสร้างสคริปต์ที่เก็บไว้ในไฟล์นั้นเหมาะสมกว่า และสามารถดำเนินการได้ตลอดเวลา ตอนนี้ หรือ ในอนาคต

ตัวดำเนินการเปรียบเทียบสตริง

ตัวดำเนินการเปรียบเทียบสตริงช่วยให้สามารถเปรียบเทียบสตริงที่เป็นตัวอักษรและตัวเลขคละกันได้ มีโอเปอเรเตอร์เหล่านี้เพียงไม่กี่ตัว ซึ่งแสดงอยู่ในรูปที่ 3

ตัวดำเนินการ คำอธิบาย
-z string จริงถ้าความยาวของสตริงเป็นศูนย์
-n สตริง จริงถ้าความยาวของสตริงไม่เป็นศูนย์
string1 ==string2

หรือ

string1 =string2
จริงถ้าสตริงเท่ากัน ตัวเดียว = ควรใช้กับคำสั่งทดสอบสำหรับความสอดคล้อง POSIX เมื่อใช้กับ [[ คำสั่ง การดำเนินการนี้จะทำการจับคู่รูปแบบตามที่อธิบายไว้ข้างต้น (คำสั่งผสม)
string1 !=string2 จริงถ้าสตริงไม่เท่ากัน
string1 จริงถ้า string1 เรียงลำดับก่อน string2 พจนานุกรม (หมายถึงลำดับการจัดเรียงเฉพาะสถานที่สำหรับตัวอักษรและตัวเลขและอักขระพิเศษทั้งหมด)
string1> string2 จริงถ้า string1 เรียงลำดับตาม string2 พจนานุกรม

รูปที่ 3:ตัวดำเนินการตรรกะสตริงทุบตี

ขั้นแรกให้ดูที่ความยาวของสตริง คำพูดรอบ ๆ $MyVar ในการเปรียบเทียบจะต้องมีการเปรียบเทียบเพื่อทำงาน (คุณควรจะยังคงทำงานใน ~/testdir .)

[student@studentvm1 testdir]$ MyVar=""; ถ้า [ -z "" ]; จากนั้น echo "MyVar มีความยาวเป็นศูนย์"; อื่น echo "MyVar มีข้อมูล"; fi
MyVar มีความยาวเป็นศูนย์
[student@studentvm1 testdir]$ MyVar="Random text"; ถ้า [ -z "" ]; จากนั้น echo "MyVar มีความยาวเป็นศูนย์"; อื่น echo "MyVar มีข้อมูล"; fi
MyVar มีความยาวเป็นศูนย์

คุณสามารถทำได้ด้วยวิธีนี้:

[student@studentvm1 testdir]$ MyVar="Random text"; ถ้า [ -n "$MyVar" ]; แล้วก้องสะท้อน "MyVar มีข้อมูล"; อื่น echo "MyVar มีความยาวเป็นศูนย์"; fi
MyVar มีข้อมูล
[student@studentvm1 testdir]$ MyVar=""; ถ้า [ -n "$MyVar" ]; แล้วก้องสะท้อน "MyVar มีข้อมูล"; อื่น echo "MyVar มีความยาวเป็นศูนย์"; fi
MyVar มีความยาวเป็นศูนย์

บางครั้งคุณอาจต้องทราบความยาวที่แน่นอนของสตริง นี่ไม่ใช่การเปรียบเทียบ แต่มันเกี่ยวข้องกัน ขออภัย ไม่มีวิธีง่ายๆ ในการกำหนดความยาวของสตริง มีหลายวิธีที่จะทำ แต่ฉันคิดว่าใช้ expr (ประเมินนิพจน์) คำสั่งที่ง่ายที่สุด อ่าน man page สำหรับ expr สำหรับข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่สามารถทำได้ โปรดทราบว่าจำเป็นต้องมีเครื่องหมายคำพูดรอบสตริงหรือตัวแปรที่คุณกำลังทดสอบ

[student@studentvm1 testdir]$ MyVar=""; expr length "$MyVar"
0
[student@studentvm1 testdir]$ MyVar="How long is this?"; expr length "$MyVar"
17
[student@studentvm1 testdir]$ expr length "เรายังสามารถหาความยาวของสตริงตามตัวอักษรได้เช่นเดียวกับตัวแปร"
70

เกี่ยวกับตัวดำเนินการเปรียบเทียบ ฉันใช้การทดสอบจำนวนมากในสคริปต์เพื่อพิจารณาว่าสองสตริงเท่ากันหรือไม่ (เช่น เหมือนกัน) ฉันใช้ตัวดำเนินการเปรียบเทียบเวอร์ชันที่ไม่ใช่ POSIX:

[student@studentvm1 testdir]$ Var1="Hello World"; Var2="สวัสดีชาวโลก"; ถ้า [ "$Var1" =="$Var2" ]; แล้ว echo "Var1 ตรงกับ Var2"; อื่น echo "Var1 และ Var2 ไม่ตรงกัน"; fi
Var1 ตรงกับ Var2
[student@studentvm1 testdir]$ Var1="Hello World"; Var2="สวัสดีชาวโลก"; ถ้า [ "$Var1" =="$Var2" ]; แล้ว echo "Var1 ตรงกับ Var2"; อื่น echo "Var1 และ Var2 ไม่ตรงกัน"; fi
Var1 และ Var2 ไม่ตรงกัน

ทดลองเพิ่มเติมด้วยตัวคุณเองเพื่อลองใช้โอเปอเรเตอร์เหล่านี้

ตัวดำเนินการเปรียบเทียบตัวเลข

ตัวดำเนินการตัวเลขทำการเปรียบเทียบระหว่างอาร์กิวเมนต์ตัวเลขสองตัว เช่นเดียวกับคลาสโอเปอเรเตอร์อื่นๆ ส่วนใหญ่เข้าใจง่าย

ตัวดำเนินการ คำอธิบาย
arg1 -eq arg2 จริงถ้า arg1 เท่ากับ arg2
arg1 -ne arg2 จริงถ้า arg1 ไม่เท่ากับ arg2
arg1 -lt arg2 จริงถ้า arg1 น้อยกว่า arg2
arg1 -le arg2 จริงถ้า arg1 น้อยกว่าหรือเท่ากับ arg2
arg1 -gt arg2 จริงถ้า arg1 มากกว่า arg2
arg1 -ge arg2 จริงถ้า arg1 มากกว่าหรือเท่ากับ arg2

รูปที่ 4:ทุบตีตัวดำเนินการเชิงตรรกะเปรียบเทียบตัวเลข

นี่คือตัวอย่างง่ายๆ อินสแตนซ์แรกตั้งค่าตัวแปร $X ถึง 1 แล้วทดสอบเพื่อดูว่า $X เท่ากับ 1 ในตัวอย่างที่สอง X ถูกตั้งค่าเป็น 0 ดังนั้นการเปรียบเทียบจึงไม่เป็นจริง

[student@studentvm1 testdir]$ X=1; ถ้า [ $X -eq 1 ]; แล้ว echo "X เท่ากับ 1"; อื่น echo "X ไม่เท่ากับ 1"; fi
X เท่ากับ 1
[student@studentvm1 testdir]$ X=0; ถ้า [ $X -eq 1 ]; แล้ว echo "X เท่ากับ 1"; อื่น echo "X ไม่เท่ากับ 1"; fi
X ไม่เท่ากับ 1
[student@studentvm1 testdir]$

ลองทำการทดลองเพิ่มเติมด้วยตัวคุณเอง

ตัวดำเนินการเบ็ดเตล็ด

โอเปอเรเตอร์เบ็ดเตล็ดเหล่านี้แสดงว่ามีการตั้งค่าตัวเลือกเชลล์หรือตัวแปรเชลล์มีค่าหรือไม่ แต่จะไม่พบค่าของตัวแปร ไม่ว่าจะมีค่าหรือไม่

ตัวดำเนินการ คำอธิบาย
-o optname จริงถ้าชื่อตัวเลือกเชลล์เปิดใช้งานอยู่ (ดูรายการตัวเลือกภายใต้คำอธิบายของ -o ตัวเลือกสำหรับชุด Bash ในตัวในหน้า Bash man)
-v varname จริงถ้ามีการตั้งค่าตัวแปรเชลล์ varname (ได้รับการกำหนดค่าแล้ว)
-R วาร์เนม จริงถ้ามีการตั้งค่าตัวแปรเชลล์ varname และเป็นชื่ออ้างอิง

รูปที่ 5:ตัวดำเนินการตรรกะ Bash เบ็ดเตล็ด

ทดลองด้วยตัวเองเพื่อลองใช้โอเปอเรเตอร์เหล่านี้

ส่วนขยาย

Bash รองรับการขยายและการทดแทนหลายประเภทซึ่งค่อนข้างมีประโยชน์ ตามหน้า man Bash Bash มีส่วนขยายเจ็ดรูปแบบ บทความนี้กล่าวถึง 5 รายการ ได้แก่ การขยายเครื่องหมายทิลเดอ การขยายเลขคณิต การขยายชื่อพาธ การขยายวงเล็บปีกกา และการแทนที่คำสั่ง

ส่วนขยายรั้ง

การขยายวงเล็บปีกกาเป็นวิธีการสร้างสตริงโดยพลการ (เครื่องมือนี้ใช้ด้านล่างเพื่อสร้างไฟล์จำนวนมากสำหรับการทดลองด้วยอักขระรูปแบบพิเศษ) การขยายวงเล็บปีกกาสามารถใช้เพื่อสร้างรายการของสตริงที่กำหนดเองและแทรกลงในตำแหน่งเฉพาะภายในสตริงสแตติกที่ล้อมรอบหรือที่ปลายด้านใดด้านหนึ่งของ สตริงคงที่ นี่อาจเป็นเรื่องยากที่จะเห็นภาพ ดังนั้นจึงเป็นการดีที่สุดที่จะทำมัน

อย่างแรก นี่คือสิ่งที่ส่วนขยายวงเล็บปีกกาทำ:

[student@studentvm1 testdir]$ echo {string1,string2,string3}
string1 string2 string3

ก็ไม่มีประโยชน์อะไรมากใช่ไหม? แต่ดูว่าเกิดอะไรขึ้นเมื่อคุณใช้มันแตกต่างออกไปเล็กน้อย:

[student@studentvm1 testdir]$ echo "สวัสดี "{David,Jen,Rikki,Jason}.
สวัสดี เดวิด สวัสดีเจน. สวัสดี ริกกี้. สวัสดีเจสัน

ดูเหมือนว่าจะมีประโยชน์—สามารถช่วยประหยัดการพิมพ์ได้มาก ลองทำสิ่งนี้:

[student@studentvm1 testdir]$ echo b{ed,olt,ar}s
beds bolts bars

ฉันสามารถไปต่อ แต่คุณก็เข้าใจ

การขยายตัวหนอน

เนื้อหาที่ขยายได้บ่อยที่สุดคือตัวหนอน (~ ) การขยาย. เมื่อคุณใช้คำสั่งนี้ในคำสั่งเช่น cd ~/Documents , Bash shell จะขยายเป็นทางลัดไปยังโฮมไดเร็กทอรีแบบเต็มของผู้ใช้

ใช้โปรแกรม Bash เหล่านี้เพื่อสังเกตผลกระทบของการขยายตัวหนอน:

[student@studentvm1 testdir]$ echo ~
/home/student
[student@studentvm1 testdir]$ echo ~/Documents
/home/student/Documents
[ student@studentvm1 testdir]$ Var1=~/Documents; ก้อง $Var1; cd $Var1
/home/student/Documents
[student@studentvm1 Documents]$

การขยายชื่อเส้นทาง

การขยายชื่อพาธเป็นคำที่ใช้ขยายรูปแบบไฟล์โกลบอล โดยใช้อักขระ ? และ * ลงในชื่อเต็มของไดเร็กทอรีที่ตรงกับรูปแบบ File globbing หมายถึงอักขระรูปแบบพิเศษที่ช่วยให้มีความยืดหยุ่นในการจับคู่ชื่อไฟล์ ไดเร็กทอรี และสตริงอื่นๆ เมื่อดำเนินการต่างๆ อักขระรูปแบบพิเศษเหล่านี้ช่วยให้จับคู่อักขระเดี่ยว หลายตัว หรือเฉพาะในสตริงได้

  • ? — จับคู่อักขระใดตัวหนึ่งในตำแหน่งที่ระบุภายในสตริงเท่านั้น
  • * — จับคู่อักขระใดๆ ตั้งแต่ศูนย์ขึ้นไปในตำแหน่งที่ระบุภายในสตริง

การขยายนี้ใช้กับชื่อไดเร็กทอรีที่ตรงกัน หากต้องการดูวิธีการทำงาน ตรวจสอบให้แน่ใจว่า testdir เป็นไดเร็กทอรีการทำงานปัจจุบัน (PWD) และเริ่มต้นด้วยรายการธรรมดา (เนื้อหาของโฮมไดเร็กทอรีของฉันจะแตกต่างจากของคุณ):

[student@studentvm1 testdir]$ ls 
chapter6  cpuHog.dos    dmesg1.txt  Documents  Music       softlink1  testdir6    Videos
chapter7  cpuHog.Linux  test dmes dmesg3.txt  file005    สาธารณะ      testdir    tmp
cpuHog     Desktop       dmesg.txt   link3      random.txt  testdir1   umask.test
[student@student$m

ตอนนี้แสดงรายการไดเร็กทอรีที่ขึ้นต้นด้วย Do , testdir/เอกสาร และ testdir/Downloads :

เอกสาร:
Directory01 FILE07 FILE15 TEST02 TEST10 TEST20 TESTFILE13 TEXTFILES
DIRECTORY02 FILE08 FILE16 TEST03 TEST11 TESTFILE01 TESTFILE14
ไฟล์ 01 FILEL17 FILE17 FILE17 FILE17 TEST12 TESTFILE04
file03 file11 file19 test06 test14 testFile09 testFile17
file04 file12 file20 test07 test15 testfile10 testfile18
file05 file13 student1.txt test08 test16 testfile11 testfile11
ดาวน์โหลด:
[student@studentvm1 testdir]$

นั่นไม่ได้ทำในสิ่งที่คุณต้องการ มันแสดงรายการเนื้อหาของไดเร็กทอรีที่ขึ้นต้นด้วย Do . ในการแสดงรายการเฉพาะไดเร็กทอรีและไม่ใช่เนื้อหาของไดเร็กทอรี ให้ใช้ -d ตัวเลือก

[student@studentvm1 testdir]$ ls -d Do*
Documents  Downloads
[student@studentvm1 testdir]$

ในทั้งสองกรณี Bash shell จะขยาย Do * รูปแบบเป็นชื่อของสองไดเร็กทอรีที่ตรงกับรูปแบบ แต่ถ้ามีไฟล์ที่ตรงกับรูปแบบด้วยล่ะ

[student@studentvm1 testdir]$ touch Downtown; ls -d Do*
เอกสาร  ดาวน์โหลด  ดาวน์ทาวน์
[student@studentvm1 testdir]$

นี่แสดงไฟล์ด้วย ดังนั้นไฟล์ใดๆ ที่ตรงกับรูปแบบจะถูกขยายเป็นชื่อเต็มด้วย

การแทนที่คำสั่ง

การแทนที่คำสั่งเป็นรูปแบบการขยายที่ช่วยให้สตรีมข้อมูล STDOUT ของคำสั่งหนึ่งใช้เป็นอาร์กิวเมนต์ของคำสั่งอื่นได้ เช่น เป็นรายการที่จะประมวลผลเป็นวง หน้าคนของ Bash กล่าวว่า:"การแทนที่คำสั่งอนุญาตให้เอาต์พุตของคำสั่งแทนที่ชื่อคำสั่ง" ฉันพบว่ามันถูกต้องถ้าดูไม่ชัด

การแทนที่นี้มีสองรูปแบบ `คำสั่ง` และ $(คำสั่ง) . ในรูปแบบเก่าโดยใช้ back tics (` ) โดยใช้แบ็กสแลช (\ ) ในคำสั่งยังคงความหมายตามตัวอักษร อย่างไรก็ตาม เมื่อใช้ในรูปแบบวงเล็บที่ใหม่กว่า แบ็กสแลชจะใช้ความหมายเป็นอักขระพิเศษ โปรดทราบด้วยว่ารูปแบบวงเล็บใช้วงเล็บเดียวในการเปิดและปิดคำสั่งคำสั่ง

ฉันมักใช้ความสามารถนี้ในโปรแกรมบรรทัดคำสั่งและสคริปต์ โดยที่ผลลัพธ์ของคำสั่งหนึ่งสามารถใช้เป็นอาร์กิวเมนต์สำหรับคำสั่งอื่นได้

เริ่มต้นด้วยตัวอย่างง่ายๆ ที่ใช้ส่วนขยายทั้งสองนี้ (อีกครั้ง ตรวจสอบให้แน่ใจว่า testdir คือผู้พิการทางสายตา):

[student@studentvm1 testdir]$ echo "Todays date is `date`"
Todays date is Sun Apr  7 14:42:46 EDT 2019
[student@studentvm1 testdir]$ echo "Todays" date is $(date)"
วันนี้คือ Sun Apr  7 14:42:59 EDT 2019
[student@studentvm1 testdir]$

-w ตัวเลือก ลำดับ ยูทิลิตี้จะเพิ่มเลขศูนย์นำหน้าให้กับตัวเลขที่สร้างขึ้นเพื่อให้มีความกว้างเท่ากัน นั่นคือ จำนวนหลักเท่ากันโดยไม่คำนึงถึงค่า ทำให้ง่ายต่อการจัดเรียงตามลำดับตัวเลข

ลำดับ ยูทิลิตี้ถูกใช้เพื่อสร้างลำดับของตัวเลข:

[student@studentvm1 testdir]$ seq 5
1
2
3
4
5
[student@studentvm1 testdir]$ echo ` seq 5`
1 2 3 4 5
[student@studentvm1 testdir]$

ตอนนี้คุณสามารถทำสิ่งที่มีประโยชน์มากขึ้นอีกเล็กน้อย เช่น สร้างไฟล์เปล่าจำนวนมากสำหรับการทดสอบ:

[student@studentvm1 testdir]$ for I in $(seq -w 5000) ; do touch file-$I ; done 

ในการใช้งานนี้ คำสั่ง seq -w 5000 สร้างรายการตัวเลขตั้งแต่หนึ่งถึง 5,000 โดยใช้การแทนที่คำสั่งเป็นส่วนหนึ่งของ สำหรับ คำสั่ง รายการตัวเลขที่ใช้โดย สำหรับ คำสั่งเพื่อสร้างส่วนตัวเลขของชื่อไฟล์

การขยายเลขคณิต

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

การขยายเลขคณิตทำงานเหมือนกับการแทนที่คำสั่งในโปรแกรมเชลล์หรือสคริปต์ ค่าที่คำนวณจากนิพจน์จะแทนที่นิพจน์สำหรับการประเมินเพิ่มเติมโดยเชลล์

อีกครั้ง เริ่มต้นด้วยสิ่งง่ายๆ:

[student@studentvm1 testdir]$ echo $((1+1))
2
[student@studentvm1 testdir]$ Var1=5; วาร์2=7; Var3=$((Var1*Var2)); echo "Var 3 =$Var3"
Var 3 =35

การหารต่อไปนี้ให้ผลลัพธ์เป็นศูนย์ เนื่องจากผลลัพธ์จะเป็นค่าทศนิยมที่น้อยกว่าหนึ่ง:

[student@studentvm1 testdir]$ Var1=5; วาร์2=7; Var3=$((Var1/Var2)); echo "Var 3 =$Var3"
Var 3 =0

นี่คือการคำนวณง่ายๆ ที่ฉันมักจะทำในสคริปต์หรือโปรแกรม CLI ซึ่งจะบอกฉันว่าฉันมีหน่วยความจำเสมือนทั้งหมดเท่าใดในโฮสต์ Linux ฟรี คำสั่งไม่ได้ให้ข้อมูลนั้น:

[student@studentvm1 testdir]$ RAM=`free | grep ^Mem | awk '{พิมพ์ $2}''; Swap=`ฟรี | grep ^สลับ | awk '{พิมพ์ $2}''; echo "RAM =$RAM และ Swap =$Swap"; echo "หน่วยความจำเสมือนทั้งหมดคือ $((RAM+Swap))";
RAM =4037080 and Swap =6291452
Total Virtual memory is 10328532

ฉันใช้ ` อักขระเพื่อคั่นส่วนของรหัสที่ใช้สำหรับการแทนที่คำสั่ง

ฉันใช้การขยายเลขคณิตของ Bash เพื่อตรวจสอบจำนวนทรัพยากรระบบในสคริปต์เป็นส่วนใหญ่ จากนั้นเลือกเส้นทางการทำงานของโปรแกรมตามผลลัพธ์

สรุป

บทความนี้ ซึ่งเป็นบทความที่สองในซีรีส์นี้เกี่ยวกับ Bash ในฐานะภาษาการเขียนโปรแกรม สำรวจไฟล์ Bash, สตริง, ตัวเลข และตัวดำเนินการทางลอจิคัลเบ็ดเตล็ดที่ให้ตรรกะการควบคุมโฟลว์การดำเนินการและการขยายเชลล์ประเภทต่างๆ

บทความที่สามในชุดนี้จะสำรวจการใช้ลูปสำหรับการดำเนินการวนซ้ำประเภทต่างๆ