วิธีย้ายไฟล์ทั้งหมดรวมถึงไฟล์ที่ซ่อนอยู่ไปยังไดเร็กทอรีหลักผ่าน *


113

คำถามนี้ต้องเป็นคำถามยอดนิยม แต่หาคำตอบไม่ได้

วิธีย้ายไฟล์ทั้งหมดผ่าน * รวมถึงไฟล์ที่ซ่อนอยู่และไปยังไดเร็กทอรีหลักเช่นนี้:

mv /path/subfolder/* /path/

การดำเนินการนี้จะย้ายไฟล์ทั้งหมดไปยังไดเร็กทอรีหลักอย่างที่คาดไว้ แต่จะไม่ย้ายไฟล์ที่ซ่อนอยู่ ต้องทำอย่างไร?


1
คำถามนี้ซ้ำกันที่ SUโดยมีคำตอบที่ถูกต้องมากกว่า (ไม่ใช่คำถามที่ยอมรับ): cp -r /path/to/source/. /destination
Florian

คำตอบ:


202

คุณสามารถค้นหาชุดโซลูชันที่ครอบคลุมเกี่ยวกับเรื่องนี้ได้ในคำตอบของ UNIX & Linux ที่ว่าคุณจะย้ายไฟล์ทั้งหมด (รวมถึงที่ซ่อนอยู่) จากไดเร็กทอรีหนึ่งไปยังอีกไดเร็กทอรีหนึ่งได้อย่างไร . แสดงโซลูชันใน Bash, zsh, ksh93, standard (POSIX) sh เป็นต้น


คุณสามารถใช้สองคำสั่งนี้ร่วมกัน:

mv /path/subfolder/* /path/   # your current approach
mv /path/subfolder/.* /path/  # this one for hidden files

หรือทั้งหมดรวมกัน ( ขอบคุณ pfnuesel ):

mv /path/subfolder/{.,}* /path/

ซึ่งขยายเป็น:

mv /path/subfolder/* /path/subfolder/.* /path/

(ตัวอย่าง: echo a{.,}bขยายเป็นa.b ab)

โปรดทราบว่านี่จะแสดงคำเตือนสองสามคำ:

mv: cannot move ‘/path/subfolder/.’ to /path/.’: Device or resource busy
mv: cannot remove /path/subfolder/..’: Is a directory

เพียงแค่เพิกเฉยต่อสิ่งเหล่านี้: สิ่งนี้เกิดขึ้นเนื่องจาก/path/subfolder/{.,}*ขยายไปยัง/path/subfolder/.และ/path/subfolder/..ซึ่งคือไดเร็กทอรีและไดเร็กทอรีหลัก (ดูWhat do“.” และ“ .. ” หมายถึงเมื่ออยู่ในโฟลเดอร์? )


หากคุณต้องการเพียงแค่คัดลอกคุณสามารถใช้เพียง:

cp -r /path/subfolder/. /path/
#                     ^
#                     note the dot!

การดำเนินการนี้จะคัดลอกไฟล์ทั้งหมดทั้งไฟล์ปกติและไฟล์ที่ซ่อนอยู่เนื่องจาก/path/subfolder/.ขยายเป็น "ทุกอย่างจากไดเร็กทอรีนี้" (ที่มา: จะคัดลอกด้วย cp เพื่อรวมไฟล์ที่ซ่อนอยู่และไดเร็กทอรีที่ซ่อนอยู่และเนื้อหาได้อย่างไร )


2
วงเล็บปีกกาเป็นเพียงการตัดสั้น ๆmv /path/subfolder/* /path/subfolder/.* /path/เท่านั้นไม่จำเป็นต้องรวมคำสั่งทั้งสองเข้าด้วยกันอย่างเคร่งครัด
chepner

7
ฉันได้รับข้อผิดพลาดต่อไปนี้:mv: overwrite `/path/.'? y mv: cannot move `/path/subfolder/.' to `/path/.': Device or resource busy mv: overwrite `/path/..'? y mv: cannot move `/path/subfolder/..' to `/path/..': Device or resource busy
เดยัน

@ เดจันเฉยเลย .หมายถึงไดเร็กทอรีปัจจุบันและ..หมายถึงupไดเร็กทอรี คุณต้องสังเกตว่ามีการย้ายไฟล์อื่น ๆ ทั้งหมด
Debiprasad

ควรค่าแก่การกล่าวถึงว่าทางลัดวงเล็บปีกกาใช้ไม่ได้กับเปลือกหอยทั้งหมด แต่คำสั่ง @chepner ฉันคิดว่ามันจะ
Jesús Carrera

7
"เพียงแค่เพิกเฉยต่อคำเตือน" อาจไม่ใช่ความคิดที่ดีเสมอไป ตอนนี้ฉันมีปัญหากับสคริปต์ที่ฉันต้องหยุดการดำเนินการหากขั้นตอนใด ๆ ล้มเหลวเนื่องจากวิธีนี้ทำให้เกิดข้อผิดพลาดอยู่เสมอจึงจะฆ่าสคริปต์ของฉัน ฉันต้องการวิธีตรวจสอบว่าคำสั่ง mv ล้มเหลวหรือไม่ ...
MarioVilas

29

ฉันคิดว่านี่เป็นสิ่งที่สง่างามที่สุดเพราะมันไม่พยายามขยับ..:

mv /source/path/{.[!.],}* /destination/path

1
ใช่ฉันสังเกตเห็นว่ามันให้ข้อความแสดงข้อผิดพลาดเหล่านั้นด้วย
Joseph Astrahan

ฉันคิดว่านี่เป็นทางออกที่ดีมาก แต่ก็ยากที่จะจำรูปแบบนั้น
Dylan B

สิ่งนี้จะพลาดไฟล์เช่น..anythingหรือ...anythingอื่น ๆ - stackoverflow.com/a/31438355/2351568มี regex ที่ถูกต้องสำหรับปัญหานี้ || แต่อย่างไรก็ตามการใช้shopt -s dotglobยังคงเป็นทางออกที่ดีกว่า!
DJCrashdummy

@DylanB อย่าท่องจำเลย จำไว้ว่าตรงกับสิ่งที่อยู่ในเครื่องหมายปีกกาโดยคั่นด้วยเครื่องหมายจุลภาค {a,b}*จะพบไฟล์ทั้งหมดที่ขึ้นต้นด้วย a หรือ b เช่น "anatomy" และ "bulldozer" การแข่งขันนัดที่สองเป็นเพียงการแข่งขันว่างเปล่าเทียบเท่า*และการแข่งขันนัดแรกเทียบเท่า.[!.]โดยที่กลุ่มนั้น[!.]หมายถึงกลุ่มที่ไม่ได้เริ่มต้นด้วยก.. วิธีนี้แต่ไม่.* ..*
mazunki

28

การดำเนินการนี้จะย้ายไฟล์ทั้งหมดไปยังไดเร็กทอรีหลักอย่างที่คาดไว้ แต่จะไม่ย้ายไฟล์ที่ซ่อนอยู่ ต้องทำอย่างไร?

คุณสามารถเปิดdotglob:

shopt -s dotglob               # This would cause mv below to match hidden files
mv /path/subfolder/* /path/

ในการปิดdotglobคุณต้องพูดว่า:

shopt -u dotglob

เป็นประโยชน์มาก ต้องการหาข้อมูลเพิ่มเติม แต่ร้านค้าเป็นแบบ builtin จึงman shoptใช้งานไม่ได้และhelp shoptสั้นมาก แต่คุณสามารถทำได้bashman () { man bash | less -p "^ $1 "; }แล้วbashman shoptอ่านทั้งหมดอย่างตรงไปตรงมา (อาจต้องกด n เพื่อข้ามลงไปที่คำสั่งถ้ามีบรรทัดที่ขึ้นต้นด้วย shopt ตามที่ฉันพบ)
Nick Rice

2
สิ่งนี้จะส่งผลต่อคำสั่งอื่น ๆ เช่นls.. ดังนั้นจึงไม่ใช่สิ่งที่คุณต้องการจริงๆอาจเป็น
phil294

5

ทางเลือกอื่นที่ง่ายกว่าคือการใช้rsyncยูทิลิตี้:

sudo rsync -vuar --delete-after --dry-run path/subfolder/ path/

หมายเหตุ: คำสั่งด้านบนจะแสดงสิ่งที่กำลังจะเปลี่ยนแปลง เพื่อดำเนินการเปลี่ยนแปลงที่เกิดขึ้นจริงลบ--dry-run

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

นอกจากนี้rsyncยังให้การสนับสนุนการคัดลอก / ย้ายไฟล์ระหว่างรีโมทและจะทำให้แน่ใจว่าไฟล์ถูกคัดลอกตรงตามเดิม ( -a)

-uพารามิเตอร์ที่ใช้จะข้ามไฟล์ที่ใหม่กว่าที่มีอยู่แล้วเก็บ-rเป็นไดเร็กทอรีและ-vจะเพิ่มความละเอียด


ทางออกที่ดีที่สุด! ในกรณีของฉันฉันเพิ่งลบพารามิเตอร์ -u ออกเพราะฉันไม่ต้องการอัปเดตโฟลเดอร์รูท ขอบคุณ
Thales Ceolin

นี่เป็นหนึ่งในคำสั่งที่หากคุณไม่ระวังคุณสามารถทำให้ตัวเองยุ่งเหยิงใน linux ได้อย่างถาวร โปรดอัปเดตคำตอบของคุณเพื่อรวม sudo ไว้ก่อนคำสั่ง rsync มิฉะนั้นผู้ใช้สามารถได้รับ Permission Denied สำหรับ mkdir ได้อย่างง่ายดาย แต่การลบไฟล์จะดำเนินต่อไปดังนั้นคำสั่ง rsync จะลบไดเร็กทอรีทั้งหมดของคุณที่คุณต้องการย้ายและไม่ทำอะไรเลย . คุณจะสูญเสียไดเรกทอรีทั้งหมดของคุณ เมื่อคุณเพิ่ม sudo ในคำตอบของคุณนี่น่าจะเป็นคำตอบที่ยอมรับได้ ดังนั้นคำสั่งควรเป็น: sudo rsync -vuar --delete-after path / subfolder / path /
Blue Water

@JohnnyB ขออภัยในความไม่สะดวก ฉันได้เพิ่มsudoและ--dry-runเพื่อให้ผู้คนสามารถทดสอบการเปลี่ยนแปลงก่อนที่จะเรียกใช้คำสั่งจริงเพื่อหลีกเลี่ยงความยุ่งเหยิงที่อาจเกิดขึ้น
kenorb

โอ้ฉันไม่รู้ว่ามีตัวเลือก --dry-run นอกจากนี้ที่ดี ไม่ต้องมีคำขอโทษ ยอดเยี่ยมมาก
Blue Water

3

ให้ฉันแนะนำคุณให้รู้จักกับ "dotglob" ของฉัน จะเปิดและปิดไม่ว่า "*" จะมีไฟล์ที่ซ่อนอยู่หรือไม่

$ mkdir test
$ cd test
$ touch a b c .hidden .hi .den
$ ls -a
. ..  .den  .hi .hidden a b c

$ shopt -u dotglob
$ ls *
a b c
$ for i in * ; do echo I found: $i ; done
I found: a
I found: b
I found: c

$ shopt -s dotglob
$ ls *
.den  .hi .hidden a b c
$ for i in * ; do echo I found: $i ; done
I found: .den
I found: .hi
I found: .hidden
I found: a
I found: b
I found: c

ค่าเริ่มต้นคือ "ปิด"

$ shopt dotglob
dotglob         off

ที่ดีที่สุดคือเปิดอีกครั้งเมื่อคุณทำเสร็จแล้วมิฉะนั้นคุณจะสับสนกับสิ่งที่คิดว่ามันจะดับลง


3

โดยใช้findคำสั่งร่วมกับmvคำสั่งคุณสามารถป้องกันไม่ให้mvคำสั่งพยายามย้ายไดเร็กทอรี (เช่น..และ.) และไดเร็กทอรีย่อย นี่คือทางเลือกหนึ่ง:

find /path/subfolder -maxdepth 1 -type f -name '*' -exec mv -n {} /path \;

มีปัญหากับคำตอบอื่น ๆ ที่ให้ไว้ ตัวอย่างเช่นแต่ละรายการต่อไปนี้จะพยายามย้ายไดเร็กทอรีย่อยจากเส้นทางต้นทาง:

1) mv /path/subfolder/* /path/ ; mv /path/subfolder/.* /path/
2) mv /path/subfolder/{.,}* /path/ 
3) mv /source/path/{.[!.],}* /destination/path

นอกจากนี้ 2) รวมถึงไฟล์. และ .. ไฟล์และ 3) คิดถึงไฟล์เช่น ..foobar, ... barfoo เป็นต้น

คุณสามารถใช้ได้mv /source/path/{.[!.],..?,}* /destination/pathซึ่งจะรวมไฟล์ที่พลาดด้วย 3) แต่ก็ยังคงพยายามย้ายไดเรกทอรีย่อย การใช้findคำสั่งด้วยmvคำสั่งตามที่ฉันอธิบายข้างต้นช่วยขจัดปัญหาเหล่านี้ทั้งหมด


2

วิธีแก้ปัญหาของฉันสำหรับปัญหานี้เมื่อฉันต้องคัดลอกไฟล์ทั้งหมด (รวมถึง.ไฟล์) ไปยังไดเร็กทอรีเป้าหมายที่รักษาสิทธิ์คือ: (เขียนทับถ้ามีอยู่แล้ว)

yes | cp -rvp /source/directory /destination/directory/

yesมีไว้สำหรับการเขียนทับไฟล์ปลายทางโดยอัตโนมัติ, rเรียกซ้ำ, vverbose, pรักษาสิทธิ์

สังเกตว่าพา ธ ต้นทางไม่ได้ลงท้ายด้วย a/ (ดังนั้นไฟล์ / ไดเร็กทอรีและไฟล์ทั้งหมดจะถูกคัดลอก)

ไดเร็กทอรีปลายทางลงท้ายด้วย/ขณะที่เรากำลังวางเนื้อหาของโฟลเดอร์ต้นทางไปยังปลายทางโดยรวม


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