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

วิธีเขียน Bash one-liners สำหรับการโคลนและจัดการที่เก็บ GitHub และ GitLab

มีบางสิ่งที่ทำให้ฉันพึงพอใจมากกว่าบรรทัด Bash อันหรูหราหนึ่งบรรทัดที่ทำงานอัตโนมัติหลายชั่วโมงที่น่าเบื่อ

ส่วนหนึ่งของการสำรวจล่าสุดในการสร้างแล็ปท็อปของฉันใหม่โดยอัตโนมัติด้วยสคริปต์ Bash (โพสต์ที่จะมาถึง!) ฉันต้องการหาวิธีที่จะโคลนที่เก็บที่โฮสต์โดย GitHub ของฉันไปยังเครื่องใหม่ได้อย่างง่ายดาย หลังจากสำรวจไปรอบ ๆ ฉันก็เขียนหนึ่งซับที่ทำอย่างนั้น

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

A Bash one-liner เพื่อโคลนที่เก็บ GitHub ทั้งหมดของคุณ

ข้อแม้:คุณต้องมีรายการที่เก็บ GitHub ที่คุณต้องการโคลน สิ่งที่ดีเกี่ยวกับเรื่องนี้คือ คุณสามารถเลือกพื้นที่เก็บข้อมูลที่คุณต้องการในเครื่องได้อย่างเต็มที่ แทนที่จะเลือกทั้งตัว

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

รับรายการ GitHub URL ในไฟล์ gh-repos.txt เช่นนี้:

[email protected]:username/first-repository.git
[email protected]:username/second-repository.git
[email protected]:username/third-repository.git

เราดำเนินการ:

xargs -n1 git clone < gh-repos.txt

สิ่งนี้จะโคลนที่เก็บทั้งหมดในรายการลงในโฟลเดอร์ปัจจุบัน ซับเดียวแบบเดียวกันนี้ใช้ได้กับ GitLab เช่นกัน หากคุณแทนที่ URL ที่เหมาะสม

เกิดอะไรขึ้นที่นี่

มีสองส่วนในหนึ่งซับนี้:อินพุต ทางด้านขวาตรงข้ามกับสัญชาตญาณ และส่วนที่ทำให้สิ่งต่าง ๆ เกิดขึ้น ทางด้านซ้าย เราสามารถจัดลำดับของส่วนต่างๆ เหล่านี้ให้เข้าใจง่ายขึ้น (อาจจะ?) โดยการเขียนคำสั่งเดียวกันดังนี้:

<gh-repos.txt xargs -n1 git clone 

ในการรันคำสั่งสำหรับแต่ละบรรทัดของอินพุตของเรา gh-repos.txt เราใช้ xargs -n1 . เครื่องมือ xargs อ่านรายการจากอินพุตและดำเนินการคำสั่งใดๆ ที่พบ (จะ echo ถ้าหาไม่เจอ) โดยค่าเริ่มต้น จะถือว่ารายการถูกคั่นด้วยช่องว่าง บรรทัดใหม่ยังใช้งานได้และทำให้รายการของเราอ่านง่ายขึ้น แฟล็ก -n1 บอก xargs เพื่อใช้ 1 อาร์กิวเมนต์ หรือในกรณีของเรา หนึ่งบรรทัดต่อคำสั่ง เราสร้างคำสั่งด้วย git clone ซึ่ง xargs จากนั้นดำเนินการสำหรับแต่ละบรรทัด ทาดา.

Bash one-liner เพื่อสร้างและพุชที่เก็บจำนวนมากบน GitLab

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

เอกสาร GitLab บอกให้เรากดสร้างโครงการใหม่โดยใช้ git push --set-upstream แต่ฉันไม่คิดว่าสิ่งนี้จะสะดวกมากสำหรับการใช้ GitLab เป็นตัวสำรอง ขณะที่ฉันทำงานกับที่เก็บของฉันในอนาคต ฉันต้องการเรียกใช้คำสั่งหนึ่งคำสั่งที่ส่งไปยังทั้ง GitHub และ GitLab โดยไม่ต้องใช้ความพยายามเพิ่มเติมในส่วนของฉัน

ในการทำให้ Bash one-liner ใช้งานได้ เราจำเป็นต้องมีรายการ URL ที่เก็บสำหรับ GitLab (ที่ยังไม่มี) เราสามารถทำได้โดยง่ายโดยการคัดลอกรายการที่เก็บ GitHub เปิดด้วย Vim และทำการค้นหาและแทนที่:

cp gh-repos.txt gl-repos.txt
vim gl-repos.txt
:%s/\<github\>/gitlab/g
:wq

สิ่งนี้สร้าง gl-repos.txt ซึ่งมีลักษณะดังนี้:

[email protected]:username/first-repository.git
[email protected]:username/second-repository.git
[email protected]:username/third-repository.git

เราสามารถสร้างที่เก็บเหล่านี้บน GitLab เพิ่ม URL เป็นรีโมต และส่งโค้ดของเราไปที่ที่เก็บใหม่โดยเรียกใช้:

awk -F'\/|(\.git)' '{system("cd ~/FULL/PATH/" $2 " && git remote set-url origin --add " $0 " && git push")}' gl-repos.txt

อดทนไว้ แล้วฉันจะอธิบายให้ฟัง ตอนนี้โปรดทราบว่า ~/FULL/PATH/ ควรเป็นเส้นทางแบบเต็มไปยังไดเร็กทอรีที่มีที่เก็บ GitHub ของเรา

เราต้องจดสมมติฐานสองสามข้อ:

  1. ชื่อของไดเร็กทอรีบนเครื่องโลคัลของคุณที่มีที่เก็บจะเหมือนกับชื่อของที่เก็บใน URL (จะเป็นกรณีนี้หากมันถูกโคลนด้วยซับในหนึ่งด้านบน)
  2. ปัจจุบันแต่ละที่เก็บถูกตรวจสอบไปยังสาขาที่คุณต้องการพุช กล่าวคือ master .

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

เกิดอะไรขึ้นที่นี่

Bash one-liner ของเราใช้แต่ละบรรทัด (หรือ URL) ใน gl-repos.txt ไฟล์เป็นอินพุต ด้วย awk มันแยกชื่อของไดเร็กทอรีที่มีที่เก็บในเครื่องของเรา และใช้ข้อมูลเหล่านี้เพื่อสร้างคำสั่งที่ใหญ่ขึ้นของเรา หากเราต้อง print ผลลัพธ์ของ awk , เราจะเห็น:

cd ~/FULL/PATH/first-repository && git remote set-url origin --add [email protected]:username/first-repository.git && git push
cd ~/FULL/PATH/second-repository && git remote set-url origin --add [email protected]:username/second-repository.git && git push
cd ~/FULL/PATH/third-repository && git remote set-url origin --add [email protected]:username/third-repository.git && git push

มาดูกันว่าเราสร้างคำสั่งนี้อย่างไร

การแยกสตริงด้วย awk

เครื่องมือ awk สามารถแยกอินพุตตามตัวคั่นฟิลด์ ตัวคั่นเริ่มต้นคืออักขระช่องว่าง แต่เราสามารถเปลี่ยนได้โดยส่ง -F ธง. นอกจากอักขระเดี่ยวแล้ว เรายังใช้ตัวคั่นฟิลด์นิพจน์ทั่วไปได้อีกด้วย เนื่องจาก URL ที่เก็บของเรามีรูปแบบที่กำหนดไว้ เราจึงสามารถคว้าชื่อที่เก็บโดยขอสตริงย่อยระหว่างอักขระทับ / และต่อท้าย URL .git .

วิธีหนึ่งในการบรรลุสิ่งนี้คือการใช้ regex \/|(\.git) :

  • \/ เป็น / . ที่ใช้ Escape ตัวละคร;
  • | หมายถึง "หรือ" บอก awk ให้ตรงกับนิพจน์ใดนิพจน์
  • (\.git) คือกลุ่มดักจับที่ส่วนท้ายของ URL ของเราที่ตรงกับ “.git” โดยมี . อักขระ. นี่เป็นการโกงเล็กน้อย เนื่องจาก “.git” ไม่ได้แบ่งแยกสิ่งใดๆ เลย (อีกด้านหนึ่งไม่มีอะไรเลย) แต่เป็นวิธีง่ายๆ ที่เราจะถอดส่วนนี้ออก

เมื่อเราบอก awk . แล้ว จะแยกที่ไหน เราสามารถคว้าสตริงย่อยที่ถูกต้องด้วยตัวดำเนินการภาคสนาม เราอ้างอิงฟิลด์ของเราด้วย $ ตามด้วยหมายเลขคอลัมน์ของฟิลด์ ในตัวอย่างของเรา เราต้องการฟิลด์ที่สอง $2 . สตริงย่อยทั้งหมดมีลักษณะดังนี้:

1: [email protected]:username
2: first-repository

ในการใช้ทั้งสตริงหรือในกรณีของเราคือ URL ทั้งหมด เราใช้ตัวดำเนินการฟิลด์ $0 . ในการเขียนคำสั่ง เราเพียงแค่แทนที่ตัวดำเนินการฟิลด์สำหรับชื่อที่เก็บและ URL เรียกใช้สิ่งนี้ด้วย print ในขณะที่เรากำลังสร้างอยู่นั้น สามารถช่วยให้แน่ใจว่าเรามีพื้นที่ทั้งหมดถูกต้อง

awk -F'\/|(\.git)' '{print "cd ~/FULL/PATH/" $2 " && git remote set-url origin --add " $0 " && git push"}' gl-repos.txt

การรันคำสั่ง

เราสร้างคำสั่งภายในวงเล็บของ system() . โดยใช้สิ่งนี้เป็นผลลัพธ์ของ awk แต่ละคำสั่งจะทำงานทันทีที่สร้างและส่งออก system() ฟังก์ชั่นสร้างโปรเซสลูกที่รันคำสั่งของเรา จากนั้นส่งคืนเมื่อคำสั่งเสร็จสิ้น ในภาษาอังกฤษแบบธรรมดา วิธีนี้ช่วยให้เราดำเนินการคำสั่ง Git ในแต่ละที่เก็บได้ทีละรายการ โดยไม่ทำลายกระบวนการหลักของเราที่ awk กำลังทำสิ่งต่าง ๆ กับไฟล์อินพุตของเรา นี่คือคำสั่งสุดท้ายของเราอีกครั้ง ทั้งหมดรวมกัน

awk -F'\/|(\.git)' '{system("cd ~/FULL/PATH/" $2 " && git remote set-url origin --add " $0 " && git push")}' gl-repos.txt

การใช้ข้อมูลสำรองของเรา

ด้วยการเพิ่ม GitLab URLs เป็นรีโมต เราได้ลดความซับซ้อนของกระบวนการพุชไปยังที่เก็บที่โฮสต์ภายนอกทั้งสอง ถ้าเราเรียกใช้ git remote -v ในไดเร็กทอรีที่เก็บของเรา เราจะเห็น:

origin  [email protected]:username/first-repository.git (fetch)
origin  [email protected]:username/first-repository.git (push)
origin  [email protected]:username/first-repository.git (push)

ตอนนี้เพียงแค่เรียกใช้ git push โดยไม่มีอาร์กิวเมนต์จะผลักสาขาปัจจุบันไปยังที่เก็บระยะไกลทั้งสอง

เราควรทราบด้วยว่า git pull โดยทั่วไปจะพยายามดึงจากที่เก็บระยะไกลที่คุณโคลนจากเดิมเท่านั้น (URL ที่ทำเครื่องหมาย (fetch) ในตัวอย่างของเราด้านบน) การดึงจากที่เก็บ Git หลายอันพร้อมกันนั้นเป็นไปได้ แต่ซับซ้อน และอยู่นอกเหนือขอบเขตของโพสต์นี้ ต่อไปนี้คือคำอธิบายของการกดและดึงไปยังรีโมตหลายตัวเพื่อช่วยให้คุณเริ่มต้นได้ หากคุณสงสัย เอกสาร Git บนรีโมทก็อาจมีประโยชน์เช่นกัน

เพื่ออธิบายรายละเอียดเกี่ยวกับความกระชับของ Bash one-liners

เมื่อเข้าใจ Bash one-liner อาจเป็นทางลัดที่สนุกและสะดวก อย่างน้อยที่สุด พึงระวังเครื่องมืออย่าง xargs และ awk สามารถช่วยทำให้การทำงานของเราเป็นไปโดยอัตโนมัติและบรรเทาความน่าเบื่อหน่ายได้มากมาย อย่างไรก็ตาม มีข้อเสียอยู่บ้าง

ในแง่ของเครื่องมือที่เข้าใจง่าย บำรุงรักษา และเข้าถึงได้นั้น Bash one-liners นั้นแย่มาก โดยทั่วไปแล้วการเขียนจะซับซ้อนกว่าสคริปต์ทุบตีโดยใช้ if หรือ while วนซ้ำและซับซ้อนกว่าในการอ่านอย่างแน่นอน เป็นไปได้ว่าเมื่อเราเขียน เราจะพลาดคำพูดเดียวหรือวงเล็บปิดที่ใดที่หนึ่ง และฉันหวังว่าบทความนี้จะแสดงให้เห็น พวกเขาสามารถอธิบายได้ไม่น้อยเช่นกัน ทำไมต้องใช้?

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

นั่นคงจะน่าพอใจไม่น้อยใช่ไหม