บทความนี้จะเปิดเผยสิ่งที่ไม่ชัดเจนที่เกี่ยวข้องกับการใช้งาน cp
เมื่อทำการคัดลอกรวมถึงวิธีการที่ช่วยให้คุณสามารถคัดลอกไฟล์จำนวนมากได้อย่างถูกต้องโดยไม่ต้องข้ามหรือหยุดทำงาน
สมมติว่าเราจำเป็นต้องคัดลอกทุกอย่างจากโฟลเดอร์ /source ไปยังโฟลเดอร์ /target
สิ่งแรกที่นึกถึงคือ:
cp /source/* /target
มาแก้ไขคำสั่งนี้ทันทีเป็น:
cp -a /source/* /target
คีย์ -a
จะเพิ่มการคัดลอกแอตทริบิวต์สิทธิ์ทั้งหมดและเพิ่มการเรียกซ้ำ เมื่อไม่จำเป็นต้องทำซ้ำสิทธิ์อย่างถูกต้อง คีย์ก็เพียงพอแล้ว -r
.
หลังจากการคัดลอก เราจะพบว่าไม่ได้คัดลอกไฟล์ทั้งหมด - ไฟล์ที่ขึ้นต้นด้วยจุด เช่น:
.profile
.local
.mc
และสิ่งที่คล้ายกัน
ทำไมสิ่งนี้ถึงเกิดขึ้น?
เนื่องจากไวด์การ์ดถูกประมวลผลโดยเชลล์ (bash
ในกรณีปกติ) ตามค่าเริ่มต้น bash จะละเว้นไฟล์ทั้งหมดที่ขึ้นต้นด้วยจุด เนื่องจากจะถือว่าไฟล์เหล่านั้นถูกซ่อนไว้ เพื่อหลีกเลี่ยงพฤติกรรมนี้ เราจะต้องเปลี่ยนพฤติกรรม bash
ใช้คำสั่ง:
shopt -s dotglob
เพื่อให้แน่ใจว่าการเปลี่ยนแปลงพฤติกรรมนี้ยังคงอยู่หลังจากการรีบูต คุณสามารถสร้างไฟล์ wildcard.sh ด้วยคำสั่งนี้ในโฟลเดอร์ /etc/profile.d
(บางทีการแจกจ่ายของคุณอาจมีโฟลเดอร์อื่น)
และหากไม่มีไฟล์ในไดเร็กทอรีต้นทางเชลล์จะไม่สามารถแทนที่สิ่งใด ๆ แทนเครื่องหมายดอกจันได้และการคัดลอกจะล้มเหลวโดยมีข้อผิดพลาดเช่นกัน มีตัวเลือกสำหรับสถานการณ์นี้ failglob
и nullglob
. เราจะต้องตั้งค่า failglob
ซึ่งจะป้องกันไม่ให้คำสั่งถูกดำเนินการ nullglob
จะไม่ทำงาน เนื่องจากจะแปลงสตริงด้วยไวด์การ์ดที่ไม่พบรายการที่ตรงกันเป็นสตริงว่าง (ความยาวเป็นศูนย์) ซึ่งสำหรับ cp
จะทำให้เกิดข้อผิดพลาด
อย่างไรก็ตาม หากมีไฟล์หลายพันไฟล์ขึ้นไปในโฟลเดอร์ ก็ควรละทิ้งแนวทางไวด์การ์ดโดยสิ้นเชิง ความจริงก็คือว่า bash
ขยายไวด์การ์ดเป็นบรรทัดคำสั่งที่ยาวมากเช่น:
cp -a /souce/a /source/b /source/c …… /target
มีการจำกัดความยาวของบรรทัดคำสั่ง ซึ่งเราสามารถค้นหาได้โดยใช้คำสั่ง:
getconf ARG_MAX
มารับความยาวสูงสุดของบรรทัดคำสั่งเป็นไบต์:
2097152
หรือ:
xargs --show-limits
เราได้รับสิ่งที่ชอบ:
….
Maximum length of command we could actually use: 2089314
….
ดังนั้น เรามาดำเนินการโดยไม่ต้องใช้ไวด์การ์ดเลย
มาเขียนกันดีกว่า
cp -a /source /target
และที่นี่เรากำลังเผชิญกับความคลุมเครือของพฤติกรรม cp
. หากไม่มีโฟลเดอร์ /target เราก็จะได้สิ่งที่ต้องการ
อย่างไรก็ตาม หากมีโฟลเดอร์เป้าหมาย ไฟล์จะถูกคัดลอกไปยังโฟลเดอร์ /target/source
เราไม่สามารถลบโฟลเดอร์ /target ล่วงหน้าได้เสมอไป เนื่องจากโฟลเดอร์นั้นอาจมีไฟล์ที่เราต้องการ และเป้าหมายของเรา เช่น คือการเสริมไฟล์ใน /target ด้วยไฟล์จาก /source
หากโฟลเดอร์ต้นทางและปลายทางชื่อเหมือนกัน เช่น เรากำลังคัดลอกจาก /source ไปยัง /home/source เราก็สามารถใช้คำสั่ง:
cp -a /source /home
และหลังจากการคัดลอก ไฟล์ใน /home/source จะถูกเสริมด้วยไฟล์จาก /source
นี่เป็นปัญหาเชิงตรรกะ: เราสามารถเพิ่มไฟล์ในไดเร็กทอรีปลายทางได้หากโฟลเดอร์มีชื่อเหมือนกัน แต่ถ้าต่างกัน โฟลเดอร์ต้นทางจะถูกวางไว้ภายในปลายทาง วิธีคัดลอกไฟล์จาก /source ไปยัง /target โดยใช้ cp โดยไม่มีไวด์การ์ด
เพื่อหลีกเลี่ยงข้อจำกัดที่เป็นอันตรายนี้ เราใช้วิธีแก้ปัญหาที่ไม่ชัดเจน:
cp -a /source/. /target
ผู้ที่คุ้นเคยกับ DOS และ Linux เข้าใจทุกอย่างแล้ว: ภายในแต่ละโฟลเดอร์จะมี 2 โฟลเดอร์ที่มองไม่เห็น “” และ “..” ซึ่งเป็นโฟลเดอร์หลอกที่ลิงก์ไปยังไดเร็กทอรีปัจจุบันและสูงกว่า
- เมื่อคัดลอก
cp
ตรวจสอบการมีอยู่และพยายามสร้าง /target/ - มีไดเร็กทอรีดังกล่าวอยู่และเป็น /target
- ไฟล์จาก /source จะถูกคัดลอกไปยัง /target อย่างถูกต้อง
ดังนั้น แขวนไว้ในกรอบหนาเพื่อความทรงจำของคุณหรือบนผนัง:
cp -a /source/. /target
พฤติกรรมของคำสั่งนี้ชัดเจน ทุกอย่างจะทำงานได้โดยไม่มีข้อผิดพลาด ไม่ว่าคุณจะมีไฟล์เป็นล้านไฟล์หรือไม่มีเลยก็ตาม
ผลการวิจัย
หากคุณต้องการคัดลอก ทั้งหมด ไฟล์จากโฟลเดอร์หนึ่งไปยังอีกโฟลเดอร์หนึ่ง เราไม่ได้ใช้ไวด์การ์ด ควรใช้แทนแทน cp
รวมกับจุดท้ายโฟลเดอร์ต้นทาง การดำเนินการนี้จะคัดลอกไฟล์ทั้งหมด รวมถึงไฟล์ที่ซ่อนอยู่ และจะไม่ล้มเหลวเมื่อมีไฟล์นับล้านหรือไม่มีไฟล์เลย
เล่ม
cp -a -T /source /target
cp -aT /source /target
หมายเหตุ: ตัวอักษร T
มีความหมาย หากคุณผสมเข้าด้วยกันคุณจะได้รับขยะที่สมบูรณ์: ทิศทางการคัดลอกจะเปลี่ยนไป
กิตติกรรมประกาศ:
- บริษัท
RUVDS.COM สำหรับการสนับสนุนและโอกาสในการเผยแพร่บนบล็อกของคุณบนHabré - ต่อภาพ
แนวคิดสามประการ . รูปภาพมีขนาดใหญ่และมีรายละเอียดมากสามารถเปิดในหน้าต่างแยกต่างหากได้
PS กรุณาส่งข้อผิดพลาดใด ๆ ที่คุณสังเกตเห็นในข้อความส่วนตัว ฉันเพิ่มกรรมของฉันเพื่อสิ่งนี้
ที่มา: will.com