ค้นหาเว็บไซต์

5 คำสั่ง Bash แบบบรรทัดเดียวที่ทำให้ฉันกลับมาใช้เทอร์มินัล Linux อยู่เสมอ


คุณใช้เวลาส่วนใหญ่ของคุณในเทอร์มินัลหรือไม่? คุณมักมองหาวิธีปรับปรุงทักษะเทอร์มินัลของคุณอยู่เสมอหรือไม่? ถ้าคุณเหมือนผม คุณคงชอบเรียนรู้วิธีใหม่ๆ ในการแก้ปัญหา เพราะมันแนะนำแนวคิดที่คุณไม่เคยจินตนาการมาก่อน ผมมีคำสั่งเทอร์มินัลแบบบรรทัดเดียวห้าคำสั่งที่ช่วยแก้ปัญหาที่พบบ่อย และบางทีอาจจะแนะนำแนวคิดใหม่ๆ ให้คุณด้วยเช่นกัน

Mkdir พร้อมการขยายวงเล็บ

การขยายวงเล็บช่วยลดความยาวคำสั่งและใช้กับทุกอย่าง

อันแรกนี้เป็นเทคนิคที่ใช้ซ้ำได้ซึ่งสามารถใช้ได้มากกว่าคำสั่งเดียว

mkdir --parents foo/{bar,baz}

คำสั่งนั้นจะสร้างโครงสร้างไดเร็กทอรีดังนี้:

foo/
├── bar/
└── baz/

แฟลก "--parents" (หรือ -p) รับประกันได้ว่าคุณสมบัติของไดเรกทอรีต้นทางจะถูกสร้างก่อน ส่วนวงเล็บปีกกาเป็นที่ซึ่งเวทมนตร์เกิดขึ้น ใน Bash พวกมันถูกเรียกว่า brace expansions และมันง่ายมาก Bash จะจัดการคำสั่งข้างต้นเหมือนว่า:

mkdir --parents foo/bar
mkdir --parents foo/baz

คุณสามารถใช้การขยายวงเล็บกับคำสั่งใดก็ได้ จากเอกสารทางการ:

chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}

Bash จะประเมินวงเล็บเคล็ดลับด้านในก่อน และนิพจน์เส้นทางก่อนหน้ากลายเป็นดังต่อไปนี้:

/usr/ucb/ex
/usr/ucb/edit
/usr/lib/ex?.?*
/usr/lib/how_ex

"?" และ "*" เป็นกลอบ (globs) ซึ่งตรงกับตัวอักษรเดียวและศูนย์หรือตัวอักษรมากกว่าหนึ่งตัวตามลำดับ

ฉันมักจะใช้การขยายวงเล็บตรง ๆ กับ mkdir ดังนั้นอย่าให้การแสดงออกที่สอง (ซับซ้อน) ทำให้คุณท้อใจ

จำนวนบรรทัดหรือคำ

สร้างสตรีมเดียวและส่งผ่านไปยัง wc

ฉันใช้คำสั่งนี้เป็นครั้งคราวเพื่อนับจำนวนบรรทัดของโค้ดในโครงการซอฟต์แวร์ของฉันหรือคำในบันทึกของฉัน

cat **/*.go | wc --lines   # Count code lines.
cat **/*.org | wc --words  # Count words in notes.

เพื่อที่จะทำการนับทั้งหมด เราจำเป็นต้องมีสตรีมข้อมูลเดียวที่ถูกส่งเข้าไปใน "wc." ถ้าเราเพียงแค่รัน wc --words **/*.org เราจะได้ผลลัพธ์หลายร้อยรายการ หนึ่งรายการสำหรับแต่ละไฟล์ คำสั่งที่ระบุแต่ละคำสั่งจะส่งสตรีมข้อมูลเดียวเข้าไป

เปรียบเทียบผลลัพธ์ของกระบวนการสองตัว

การแทนที่กระบวนการทำให้คำสั่ง diff มีประโยชน์มากขึ้น

คุณอาจคุ้นเคยกับ diff ซึ่งช่วยให้คุณเปรียบเทียบไฟล์สองไฟล์ได้:

diff foo.txt bar.txt

อย่างไรก็ตาม คุณอาจไม่ทราบเกี่ยวกับการแทนที่กระบวนการ สิ่งเหล่านี้ช่วยให้คุณสามารถเรียกใช้คำสั่งสองคำสั่งใดก็ได้และส่งผลลัพธ์ของมัน (เป็นเส้นทางไปยังไฟล์ชั่วคราว) ให้กับคำสั่งเช่น diff:

diff <(ls ./foo) <(ls ./bar)

เมื่อพิจารณาโครงสร้างไดเรกทอรีดังต่อไปนี้ (ทั้งคู่มีไฟล์ชื่อ "two")

.
├── bar
│   ├── three
│   └── two
└── foo
    ├── one
    └── two

เครื่องหมาย ">" บ่งชี้ว่าการแทนที่กระบวนการทางด้านขวา ("<(ls ./bar)") แสดงรายการไฟล์ชื่อ "three" แต่ด้านซ้ายไม่แสดง หลักการเดียวกันนี้ใช้กับ "<" ด้วย

แนวทางที่มีประโยชน์มากกว่าคือการสร้างเกณฑ์มาตรฐานของไดเรกทอรี (ls ~/foo > foo-baseline.txt) และเปรียบเทียบกับรายการปัจจุบัน:

diff foo-baseline.txt <(ls ~/foo)

ตอนนี้เราสามารถเห็นการเปลี่ยนแปลงใด ๆ ในไดเรกทอรี สิ่งนี้มีประโยชน์มากโดยเฉพาะเมื่อใช้ watch (ซึ่งจะกล่าวถึงในหัวข้อต่อไป)

การแทนที่ด้วยกระบวนการช่วยให้คุณเปรียบเทียบคำสั่งใด ๆ สองคำสั่งได้ ดังนั้นคุณสามารถปล่อยจินตนาการของคุณไปไกลกว่าคำสั่ง "ls" ธรรมดา ๆ

ดูผลลัพธ์ของคำสั่ง

การเฝ้าติดตามการเปลี่ยนแปลงมักจำเป็น และคำว่า "watch" มีความยืดหยุ่น

ยูทิลิตี้ "watch" นั้นเรียบง่ายมาก: มันจะตรวจสอบคำสั่งทุกสองวินาที ทำให้คุณสามารถติดตามมันเพื่อดูการเปลี่ยนแปลงได้

ตัวอย่างง่ายๆ คือการตรวจสอบพอร์ตที่กำลังฟัง:

watch ss -altpn

มันล้างหน้าจอและแสดงเฉพาะผลลัพธ์ของคำสั่งพร้อมหัวข้อขนาดเล็ก

แฟล็ก --color แปลความรหัส ANSI และ --differences แสดงการเปลี่ยนแปลงระหว่างรอบการทำซ้ำ อย่างไรก็ตาม ผลลัพธ์แตกต่างกันไป และค่อนข้างไม่น่าเชื่อถือ

เราสามารถใช้ "watch" เพื่อตรวจสอบไดเรกทอรีของเราและแสดงความแตกต่างได้:

watch "bash -c 'diff foo-baseline.txt <(ls -1 foo/)'"

คำสั่ง "watch" ใช้ sh ซึ่งไม่มีการแทนที่กระบวนการของ Bash ให้รันคำสั่ง diff ผ่าน Bash โดยตรงเพื่อเปิดใช้งานฟีเจอร์นั้น

การสร้างไฟล์ ("1") ทำให้มันปรากฏใน diff ("2") ตอนนี้คุณจะได้รับอัปเดตเกือบเรียลไทม์เกี่ยวกับการเปลี่ยนแปลงในไดเรกทอรีในรูปแบบ diff

ค้นหาด้วย Grep ระหว่างรูปแบบเฉพาะ

บางครั้งคุณอาจต้องการตัดส่วนของข้อความออก

Grep จับคู่ทั้งบรรทัดทั้งหมด แต่บางครั้งคุณอาจต้องการเพียงส่วนที่ตรงกับรูปแบบเท่านั้น ตัวอย่างเช่น หากคุณต้องการดึงเฉพาะ เนื้อหา ของแท็ก HTML:

<body>
  <p>The text we care about.</p>
</body>
grep -oP '(?<=<p>).+(?=</p>)'

  • "-o": คืนเฉพาะส่วนที่ตรงกันของบรรทัด ไม่ใช่ทั้งหมด
  • "-P": ใช้ regex แบบเข้ากันได้กับ Perl ซึ่งช่วยให้สามารถใช้ positive lookaheads และ lookbehinds ได้
  • "(?<=

    )": การมองย้อนกลับเชิงบวก หมายถึงว่า เมื่อจับคู่รูปแบบ (".+") เครื่องยนต์จะมองย้อนกลับไปเพื่อดูว่า "

    " ก็ตรงกันด้วยหรือไม่

  • "(?=

    )": การมองไปข้างหน้าแบบบวก มันคล้ายกับการมองถอยหลังแบบบวก แต่จะมองไปข้างหน้า

โดยพื้นฐานแล้ว regex จะจับคู่กับ ".+" (อักขระใด ๆ หนึ่งตัวหรือมากกว่า) และตรวจสอบทั้งสองด้านเพื่อดูว่า "

" และ "

" ตรงกันด้วยหรือไม่ หากไม่ตรงกัน การจับคู่จะล้มเหลว ซึ่งช่วยให้เราสามารถเน้นแท็ก "p" ได้ คุณสามารถใช้รูปแบบใดก็ได้ตามที่คุณต้องการ; ฉันใช้ HTML เป็นเพียงตัวอย่างเท่านั้น ตัวอย่างเช่น:

grep -oP '(?<=foo).+(?=bar)'

คำสั่งนั้นจะตรงกับอะไรก็ได้ระหว่าง "foo" และ "bar"

เวอร์ชันเก่าของ PCRE จะยอมรับเฉพาะ lookbehind ที่ความยาวคงที่เท่านั้น (ไม่อนุญาตให้ใช้ ?, + หรือ *) อย่างไรก็ตาม ตั้งแต่เวอร์ชัน 10.43 (PCRE2) จะอนุญาตให้มีขีดจำกัดปรับได้ (ค่าเริ่มต้น 255 ตัวอักษร) ขีดจำกัดนี้ถูกตั้งขึ้นเพื่อป้องกันการประมวลผลที่มีประสิทธิภาพต่ำ การรัน grep --version ควรจะแสดงว่าใช้เวอร์ชัน PCRE ใด

ฉันมีคู่มือเกี่ยวกับ regex ที่ละเอียดกว่านี้ซึ่งอาจทำให้คุณสนใจ มันครอบคลุมทุกองค์ประกอบพื้นฐาน


คำสั่งเหล่านี้ขึ้นอยู่กับสถานการณ์เป็นอย่างมาก แต่ก็ให้ข้อมูลเชิงลึกที่สามารถนำไปใช้กับคำสั่งอื่น ๆ ได้หลายคำสั่ง การขยายเครื่องหมายวงเล็บใช้ได้กับเกือบทุกคำสั่งที่นึกออกและมีประโยชน์โดยเฉพาะกับเส้นทางระบบไฟล์ Watch คือสิ่งที่ฉันใช้บ่อย และ diffs ครอบคลุมสถานการณ์ที่เราต้องติดตามการเปลี่ยนแปลง Grep และ regex มีความสามารถอย่างมาก แต่ก็มีหลายโอกาสในอดีตที่ฉันไม่สามารถตัดส่วนของข้อความออกได้—ตอนนี้ฉันรู้วิธีแล้ว และคุณก็เช่นกัน

บทความที่เกี่ยวข้อง