CP ไฟล์ที่ซ่อนอยู่กับรูปแบบ glob


13

สถานการณ์:

$ mkdir foo && touch foo/.test
$ cp foo/* .
zsh: no matches found: foo/*
(or bash : cp: cannot stat foo/*’: No such file or directory)

ฉันมีไดเรกทอรีที่เต็มไปด้วยโฟลเดอร์และไฟล์ที่ซ่อนอยู่ เกิดอะไรขึ้นและทางออกคืออะไร?


dotglobจะแปลให้globdotsโดยzshซึ่งเป็นชื่อตัวเลือกที่ถูกต้องสำหรับการทุบตี

คำตอบ:


19

คำเตือน: คำตอบนี้เกี่ยวข้องกับ Bash โดยเฉพาะ แต่ส่วนใหญ่เกี่ยวข้องกับคำถามเกี่ยวกับรูปแบบ glob!

ตัวละครดาว ( *) เป็นสัญลักษณ์แทน มีชุดอักขระบางตัวที่จะแทนที่และอักขระตัวแรกที่เป็นจุด ( .) ไม่ใช่หนึ่งในนั้น นี่เป็นกรณีพิเศษเนื่องจากวิธีการทำงานของระบบไฟล์ Unix ไฟล์ที่ขึ้นต้นด้วยจุดนั้นถือว่าเป็น "ซ่อน" นั่นหมายความว่าเครื่องมือเช่นcp, lsฯลฯ จะไม่ได้ "เห็น" พวกเขาจนกว่าบอกอย่างชัดเจนที่จะทำเช่นนั้น

ตัวอย่าง

ก่อนอื่นเรามาสร้างข้อมูลตัวอย่าง

$ mkdir .dotdir{1,2} regdir{1,2}
$ touch .dotfile{1,2} regfile{1..3}

ดังนั้นตอนนี้เรามีดังต่อไปนี้:

$ tree -a
.
|-- .dotdir1
|-- .dotdir2
|-- .dotfile1
|-- .dotfile2
|-- regdir1
|-- regdir2
|-- regfile1
|-- regfile2
`-- regfile3

ตอนนี้มาเล่นเกมกันบ้าง คุณสามารถใช้คำสั่งechoเพื่อแสดงรายการไวด์การ์ด ( *) เฉพาะสำหรับคำสั่งที่กำหนดดังนี้:

$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3


$ echo reg*
regdir1 regdir2 regfile1 regfile2 regfile3

$ echo .*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2

$ echo .* *
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3

$ echo .dotdir*
.dotdir1 .dotdir2

เปลี่ยนพฤติกรรมหรือไม่

คุณสามารถใช้คำสั่งshopt -s dotglobที่จะเปลี่ยนพฤติกรรมของ*เพื่อที่นอกเหนือไปจากไฟล์เช่นมันจะตรงกับregfile1.dotfile1

ตัดตอนมาจากbashหน้าคน

dotglob If set, bash includes filenames beginning with a `.' in the results 
        of pathname expansion.

ตัวอย่าง:

$ shopt -s dotglob
$ echo *
.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3

คุณสามารถย้อนกลับพฤติกรรมนี้ได้ด้วยคำสั่งนี้:

$ shopt -u dotglob
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3

สถานการณ์ของคุณ?

สำหรับคุณคุณกำลังบอกcpว่าคุณต้องการคัดลอกไฟล์ทั้งหมดที่ตรงกับรูปแบบ*และไม่มีไฟล์ใด ๆ

$ cp foo/.* .

หรือคุณสามารถทำได้ถ้าคุณต้องการทุกอย่างในfooโฟลเดอร์:

$ cp foo .

หรือคุณชัดเจน:

$ cp foot/.* foo/* .

รูปแบบกะทัดรัดมากขึ้นโดยใช้การขยายรั้งในbash:

$ cp foo/{.,}* .

เมื่อใดก็ตามที่คุณสามารถใช้echoเคล็ดลับเพื่อดูรูปแบบไฟล์ที่คุณนำเสนอ

$ echo {.,}*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 abc regdir1 regdir2 regfile1 regfile2 regfile3

อนึ่งหากคุณกำลังจะคัดลอกไดเรกทอรีของไฟล์ + ไดเรกทอรีอื่น ๆ คุณมักจะต้องการทำสิ่งนี้ซ้ำแล้วซ้ำอีกนั่นคือ-Rสวิตช์ไปที่cp:

$ cp -R foo/. .

1
คุณอาจต้องการที่จะพูดถึงการใช้งานของshopt -s dotglob, echo *จากนั้นให้:.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
Drav โลน

@DravSloan - ขอบคุณสำหรับคำแนะนำ เพิ่มมัน
slm

cp -r foo .โดยทั่วไปจะไม่สามารถทำงานได้เนื่องจากcpจะปฏิเสธที่จะคัดลอกมากกว่าตัวเองคุณอาจจะหมายถึงfoo cp -R foo/. .(โปรดทราบว่าcp -Rเป็นมาตรฐานหนึ่ง)
Stéphane Chazelas

1
นอกจากนี้ทราบว่า (ค่อนข้างสมเหตุสมผล) zshไม่รวม.และในการขยายตัวของ.. .*ในzshหากรูปแบบไม่ตรงกันคำสั่งจะถูกยกเลิก (ค่อนข้างสมเหตุสมผลอีกครั้ง) ดังนั้นในกรณีทั่วไปcp foo/{,.}* .จะล้มเหลวหากไม่มีไฟล์ที่ซ่อนอยู่หรือไม่มีไฟล์ที่ไม่ถูกซ่อน
Stéphane Chazelas

7
คำตอบนี้ใช้กับการทุบตีเท่านั้น ผู้ถามใช้ zsh ซึ่งคำตอบนั้นง่ายกว่ามากและshoptไม่มีอยู่จริง
Gilles 'หยุดความชั่วร้าย'

31

ด้วยzshวิธีทั่วไปคือการใช้โปรแกรมขยายD รอบตัว (เพื่อรวมไฟล์ [D] ot):

cp foo/*(D) .

โปรดทราบว่ามีหรือไม่มีDzsh globs จะไม่รวม.หรือไม่..(ตามที่คุณคาดหวัง)


4

เชลล์ดำเนินการกับไฟล์เหล่านั้นว่าซ่อนอยู่เมื่อแก้ไข*อักขระดังนั้นจึงcpไม่ได้รับชื่อไฟล์ใด ๆ เหล่านี้เป็นอาร์กิวเมนต์

คุณสามารถคัดลอกพวกเขาโดยระบุอย่างชัดเจน cp foo/.* .


1

หากสิ่งที่คุณต้องการทำคือคัดลอกไฟล์ & ไดเรกทอรีทั้งหมดจากที่หนึ่งไปอีกที่หนึ่งคุณสามารถใช้rsyncคำสั่งมาตรฐาน ในตัวอย่างที่คุณให้ไว้ข้างต้น:

mkdir foo && touch foo/.test
rsync -a foo/ .

จะทำการคัดลอกเนื้อหาทั้งหมดซ้ำfooรวมถึงไฟล์ที่ซ่อนอยู่และไดเรกทอรีที่ซ่อนอยู่ลงในไดเรกทอรีปัจจุบัน เครื่องหมายทับท้ายที่foo/มีความสำคัญในการ rsync; กับมันเท่านั้นเนื้อหาของfooจะถูกคัดลอกโดยไม่ต้อง rsync จะคัดลอกfooเช่นกัน ตัวอย่างเช่น:-

mkdir src && mkdir dest && touch src/.test
rsync -a src  dest    // copies 'src' contents to 'dest/src'
rsync -a src/ dest    // copies 'src' contents to 'dest' 

มีตัวเลือกอื่น ๆ ที่ปรับแต่ง rsync รวมถึงการคัดลอกระหว่างเครื่อง


1

คำตอบ zsh ของStéphane Chazelas นั้นถูกต้องสำหรับนิพจน์เดียวที่มี glob ในนั้น อย่างไรก็ตามหากคุณต้องการตั้งค่าสำหรับนิพจน์ทั้งหมดตามค่าเริ่มต้นคุณสามารถใช้

setopt GLOB_DOTS

ใส่ไว้ในของคุณ~/.zshrcเพื่อให้ถาวร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.