คุณจะย้ายไฟล์ทั้งหมด (รวมถึงที่ซ่อนอยู่) จากไดเรกทอรีหนึ่งไปยังอีกไดเรกทอรีหนึ่งได้อย่างไร?


132

ฉันจะย้ายไฟล์ทั้งหมดในไดเรกทอรี (รวมถึงไฟล์ที่ซ่อนอยู่) ไปยังไดเรกทอรีอื่นได้อย่างไร

ตัวอย่างเช่นหากฉันมีโฟลเดอร์ "Foo" ที่มีไฟล์ ".hidden" และ "notHidden" อยู่ภายในฉันจะย้ายไฟล์ทั้งสองไปยังไดเรกทอรีที่ชื่อ "Bar" ได้อย่างไร ข้อมูลต่อไปนี้ใช้ไม่ได้เนื่องจากไฟล์ ".hidden" ยังคงอยู่ใน "Foo"

mv Foo/* Bar/

ลองด้วยตัวคุณเอง

mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/


Bah ฉันรู้ว่าฉันควรจะรีเฟรชคำตอบก่อนที่จะพิมพ์ออกมา ลิงค์ที่มีประโยชน์มาก
Steven D

น่าเสียดายที่คำถามนี้จบลงที่นี่เพราะฉันบอกว่ามันควรจะย้ายที่นี่หรือ SU ดังนั้นแน่นอนว่ามันย้ายมาที่นี่เมื่อมีการซ้ำซ้อนกับ SU แล้ว :)
Michael Mrozek

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

คำตอบ:


151

zsh

mv Foo/*(DN) Bar/

หรือ

setopt -s glob_dots
mv Foo/*(N) Bar/

(ออก(N)หากคุณรู้ว่าไดเรกทอรีไม่ว่างเปล่า)

ทุบตี

shopt -s dotglob nullglob
mv Foo/* Bar/

Ksh93

หากคุณรู้ว่าไดเรกทอรีไม่ว่างเปล่า:

FIGNORE='.?(.)'
mv Foo/* Bar/

Standard (POSIX) sh

for x in Foo/* Foo/.[!.]* Foo/..?*; do
  if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done

หากคุณยินดีที่จะให้mvคำสั่งคืนสถานะข้อผิดพลาดแม้ว่าจะสำเร็จก็เป็นเรื่องง่ายขึ้นมาก:

mv Foo/* Foo/.[!.]* Foo/..?* Bar/

GNU find และ GNU mv

find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +

ค้นหามาตรฐาน

หากคุณไม่สนใจที่จะเปลี่ยนเป็นไดเรกทอรีต้นทาง:

cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} + -type d -prune

ต่อไปนี้เป็นรายละเอียดเพิ่มเติมเกี่ยวกับการควบคุมว่าไฟล์ดอทจับคู่เป็น bash, ksh93 และ zsh

ทุบตี

ตั้งค่าตัวเลือกdotglob

$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero

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

$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one

Ksh93

ตั้งค่าตัวแปรFIGNORE หากไม่มีการตั้งค่า (ค่าเริ่มต้น), .*เปลือกทำงานเป็นถ้าค่าเป็น หากต้องการละเว้น.และ..ต้องจับคู่อย่างชัดเจน (คู่มือใน ksh 93s + 2008-01-31 ระบุว่า.และ..จะถูกละเว้นเสมอ แต่สิ่งนี้ไม่ได้อธิบายพฤติกรรมที่แท้จริงอย่างถูกต้อง)

$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero

คุณสามารถรวมไฟล์ dot ในรูปแบบโดยจับคู่กับไฟล์เหล่านั้นอย่างชัดเจน

$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero

จะมีการขยายตัวออกมาว่างเปล่าถ้าไดเรกทอรีที่ว่างเปล่าให้ใช้Nรูปแบบตัวเลือกที่ตรงกับ: หรือ~(N)@(*|.[^.]*|..?*)~(N:*|.[^.]*|..?*)

zsh

ตั้งค่าตัวเลือกdot_glob

% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero

.และ..จะไม่ตรงกันแม้ว่ารูปแบบจะตรงกับส่วนนำ.อย่างชัดเจน

% echo .*
..two .one

คุณสามารถรวมจุดไฟล์ในรูปแบบเฉพาะด้วยตัวระบุแบบD หมุนได้

% echo *(D)
..two .one none zero

เพิ่มNรอบคัดเลือก glob ที่จะทำให้การขยายตัวออกมาว่างเปล่าใน directory *(DN)ว่าง:


หมายเหตุ: คุณอาจได้รับผลการขยายตัวชื่อไฟล์ในการสั่งซื้อที่แตกต่างกัน (เช่นnoneตามด้วย.oneตามด้วย..two) ตามการตั้งค่าของคุณLC_COLLATE, LC_ALLและLANGตัวแปร


1
ทำไมnullglob? มันจะสมเหตุสมผลมากกว่าถ้าจะยกเลิกmvคำสั่ง (เช่น fish, csh / tcsh, zsh (ไม่มี(N)) ทำ, หรือ bash กับ failglob) มากกว่าการรันmv /Bar/คำสั่งที่ทำให้รู้สึกน้อย
Stéphane Chazelas

1
ฉันจะบอกว่าคำอธิบาย GLOBIGNORE ของคุณไม่ถูกต้องและทำให้เข้าใจผิด การตั้งค่า GLOBIGNORE เป็นค่าที่ไม่ว่างจะเปิดเป็น dotglob และสร้าง.และ..ไม่จับคู่ (เช่นในเชลล์ที่มีเหตุผลอื่น ๆ เช่น zsh, ปลา, pdksh และอนุพันธ์) แม้ว่าคุณจะเปลี่ยน dotglob ออกไปในภายหลัง ( GLOBIGNORE=:; shopt -u dotglob; echo .*จะไม่ส่งออก.และ..) การตั้งค่า GLOBIGNORE เป็น.:..หรือ.หรือ:มีผลเหมือนกัน
Stéphane Chazelas

ksh93มักจะเพิกเฉย.และ..ดูเหมือนว่าจะถูกทำลายในระหว่างksh93k+(ที่มันทำงาน) และksh93m(ที่มันไม่ทำงานอีกต่อไป) โปรดทราบว่ามันไม่ดีในการที่ksh93จะใช้ค่าของ FIGNORE จากสภาพแวดล้อมดังนั้นตัวอย่างเช่นFIGNORE='!(..)'env สามารถสร้างความเสียหายได้
Stéphane Chazelas

24
#!/bin/bash

shopt -s dotglob
mv Foo/* Bar/

จาก man bash

dotglobหากตั้งค่า bash จะมีชื่อไฟล์ที่ขึ้นต้นด้วย '.' ในผลลัพธ์ของการขยายชื่อพา ธ


ด้วยข้อสังเกตที่ว่าคำสั่งนี้จะส่งคืนรหัสข้อผิดพลาดหากไดเรกทอรีว่างเปล่า (แม้ว่าคำสั่งจะดำเนินการตามจริง)
Gilles

1
@Gilles ข้อผิดพลาดจากนั้นจะmvบ่นว่าไฟล์ที่เรียกว่าFoo/*ไม่มีอยู่ น่าสนใจถ้าFooค้นหาได้ แต่อ่านไม่ได้และมีไฟล์ชื่อ*อยู่ในนั้นคุณจะไม่ได้รับข้อผิดพลาดไฟล์นั้นจะถูกย้าย แต่ไม่ใช่ไฟล์อื่นในไดเรกทอรี bashมีfailglobตัวเลือกอื่น ๆ มันจะทำงานมากขึ้นเช่นzsh, fishหรือcsh/ tcshและยกเลิกคำสั่งที่มีข้อผิดพลาดเมื่อ glob ไม่สามารถขยายได้แทนการว่าพฤติกรรมของปลอมออกจาก glob ตามที่เป็น
Stéphane Chazelas

7

วิธีง่ายๆในการทำสิ่งนี้bashคือ

mv {Foo/*,Foo/.*} Bar/

แต่จะย้ายไดเรกทอรี

หากคุณต้องการย้ายไฟล์ทั้งหมดรวมถึงที่ซ่อนอยู่ แต่ไม่ต้องการย้ายไดเรกทอรีใด ๆ คุณสามารถใช้สำหรับลูปและทดสอบ

for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;


4

วิธีหนึ่งคือการใช้find:

find Foo/ -type f -exec mv -t Bar/ {} \+

-type fจำกัด การค้นหาคำสั่งในการค้นหาไฟล์ คุณควรตรวจสอบ-type, -maxdepthและ-mindepthตัวเลือกfindในการปรับแต่งคำสั่งของคุณไปยังบัญชีสำหรับไดเรกทอรีย่อย ค้นหามีความยาว แต่มีประโยชน์มากหน้าคู่มือ


3
ซึ่งจะย้ายเฉพาะไฟล์ปกติFoo/ไม่ใช่ไดเรกทอรีย่อยและไฟล์อื่น ๆ
Gilles

2

ลองใช้คำสั่ง copy cp:

$ cp -r myfolder/* destinationfolder

cp -r หมายถึงการคัดลอกซ้ำดังนั้นโฟลเดอร์และไฟล์ทั้งหมดจะถูกคัดลอก

คุณสามารถใช้คำสั่งrmremove เพื่อลบโฟลเดอร์:

$ rm -r myfolder

ดูเพิ่มเติมได้ที่: ย้ายไฟล์ทั้งหมดจากไดเรกทอรีไปยังอีกที่หนึ่ง


2
ไม่ใช่สิ่งที่ดีที่สุดเมื่อคุณย้ายไฟล์ขนาดใหญ่จำนวนมาก แต่ฉันคิดว่ามันจะใช้งานได้
คอรีไคลน์

บางทีถ้าคุณใช้จุดแทนที่จะเป็นดาวล่ะ?
วิน

1

Rsync เป็นอีกทางเลือกหนึ่ง:

rsync -axvP --remove-source-files sourcedirectory/ targetdirectory

สิ่งนี้ใช้งานได้เพราะใน rsync เรื่องสแลชต่อท้ายsourcedirectory/หมายถึงเนื้อหาของไดเรกทอรีในขณะที่sourcedirectoryจะอ้างถึงไดเรกทอรีเอง

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

ย้ายไฟล์และลบไดเรกทอรีด้วย rsync หรือไม่

ดังนั้นในขณะที่สิ่งนี้อาจไม่เหมาะสำหรับการย้ายงาน แต่ก็มีประโยชน์อย่างมากสำหรับการถ่ายเอกสาร


1

คำตอบสำหรับทุบตี / ปลา

นี่คือวิธีการใช้สัญลักษณ์แทน:

.[!.]* ..?*จะจับคู่ไฟล์ที่ซ่อนทั้งหมดยกเว้น.และ..

.[!.]* ..?* *จะจับคู่ไฟล์ทั้งหมด (ซ่อนหรือไม่)ยกเว้น.และ..

และเพื่อตอบตัวอย่างเฉพาะของคำถามนี้ที่คุณต้องการ cd foo && mv .[!.]* ..?* * ../bar

คำอธิบาย

.[!.]*ตรงกับชื่อไฟล์ที่เริ่มต้นด้วยจุดหนึ่งจุดตามด้วยตัวอักษรใด ๆ ยกเว้นจุดเลือกตามด้วยสตริง นี้อยู่ใกล้ ..fooแต่พอคิดถึงไฟล์ที่เริ่มต้นด้วยจุดสองจุดเช่น ที่จะรวมไฟล์ดังกล่าวเราเพิ่ม..?*ซึ่งตรงกับชื่อไฟล์ที่เริ่มต้นด้วยจุดสองจุดตามด้วยตัวอักษรใด ๆเลือกตามด้วยสตริง

ทดสอบ

คุณสามารถทดสอบอักขระตัวแทนเหล่านี้ด้วยคำสั่งด้านล่าง ฉันลองพวกมันเรียบร้อยแล้วภายใต้การทุบตีและปลา พวกเขาล้มเหลวภายใต้ sh, zsh, xonsh

mkdir temp
cd temp
touch  a  .b  .bc  ..c  ..cd  ...d  ...de
ls .[!.]* ..?*
# you get this output:
          .b  .bc  ..c  ..cd  ...d  ...de
# cleanup
cd ..
rm -rf temp

0

คุณอาจสามารถค้นหาและ grep ด้วย backquotes เพื่อเลือกไฟล์สำหรับคำสั่ง move ส่งต่อไปยัง mv

เช่นสำหรับไฟล์ที่ซ่อนอยู่

find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden

ดังนั้น

mv `find Foo -maxdepth 1 | egrep '^Foo/[.]'` Bar # mv Foo/.hidden Bar

ย้ายเฉพาะไฟล์ที่ซ่อนอยู่ที่เลือกลงในBar:

mv `find Foo -maxdepth 1 | egrep '^Foo/.'` Bar # mv Foo/.hidden Foo/notHidden Bar

ย้ายไฟล์ทั้งหมดใน Foo to Bar ตั้งแต่ '.' ในคำสั่ง egrep ทำหน้าที่เป็นสัญลักษณ์แทนโดยไม่มีเครื่องหมายวงเล็บเหลี่ยม

^ตัวอักษรเพื่อให้แน่ใจว่าการแข่งขันจะเริ่มต้นจากจุดเริ่มต้นของบรรทัด

รายละเอียดบางส่วนของegrepการจับคู่แบบที่สามารถพบได้ที่นี่

การใช้maxdepth 1หยุดการค้นหาจากการเข้าไปในไดเรกทอรีย่อย


0

แรงบันดาลใจจากคำตอบนี้ :

โดยไม่ต้องคัดลอกไฟล์ ...

rsync -ax --link-dest=../Foo/ Foo/ Bar

คำเตือน:

  • --link-destเส้นทางต้องเป็นแบบสัมบูรณ์หรือสัมพันธ์กับ DESTINATION ( Bar ในตัวอย่าง)

  • คุณต้องใส่/SOURCE ( Foo/ในตัวอย่าง) มิฉะนั้นจะคัดลอกโฟลเดอร์ SOURCE แทนที่จะเป็นเนื้อหาของมัน


0

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

mv sourcedir/{*,.[^.]*} destdir/

แก้ไข:

ดังนั้นตามที่ G-man กล่าวคำตอบดั้งเดิมของฉันไม่ได้เป็นไปตามมาตรฐาน posix และค่อนข้างเหมือนกับคำตอบ ndemou ของข้างต้นด้วยการเปลี่ยนแปลงครั้งเดียวซึ่งใช้การขยายรั้งเพื่อสร้างรายการของสตริงที่มีการดำเนินการแล้ว นี่หมายความว่าคุณไม่จำเป็นต้องcdเข้าไปในไดเรกทอรีต้นทาง ไม่ว่าจะเป็นการเปลี่ยนแปลงครั้งใหญ่ แต่มันแตกต่างกัน

ตัวอย่าง: สมมติว่าคุณมีเค้าโครงต่อไปนี้แล้ว

 $ tree -a
.
├── destdir
└── sourcedir
    ├── ..d1
    ├── ..d2
    ├── ..double
    ├── file-1
    ├── file-2
    ├── .hidden-1
    ├── .hidden-2
    ├── ...t1
    └── ...t2

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

mv sourcedir/{*,.[!.]*,..?*} destdir/

สิ่งนี้ได้รับการขยายไปยังสิ่งต่อไปนี้:

mv sourcedir/file-1 sourcedir/file-2 sourcedir/.hidden-1 sourcedir/.hidden-2 sourcedir/..d1 sourcedir/..d2 sourcedir/..double sourcedir/...t1 sourcedir/...t2 destdir/

ตอนนี้คุณควรเห็นไฟล์ทั้งหมดที่อยู่ในdestdir :

 $ tree -a
.
├── destdir
   ├── ..d1
   ├── ..d2
   ├── ..double
   ├── file-1
   ├── file-2
   ├── .hidden-1
   ├── .hidden-2
   ├── ...t1
   └── ...t2
└── sourcedir

คุณสามารถทำสิ่งดีๆได้ด้วยวงเล็บปีกกาด้วยการเพิ่มเติมใน 4.x ลองใช้bash-hackersสำหรับตัวอย่างที่ดี


1
นี่เป็นคำตอบที่ซ้ำกันโดยทั่วไปยกเว้นคุณเพิ่มวงเล็บปีกกา (โดยไม่ต้องอธิบาย) แต่ (1) คำตอบของคุณไม่ตรงกับชื่อไฟล์ที่ขึ้นต้นด้วย..และ (2) เป็นไปตาม POSIXคุณควรใช้!แทน^; เช่น  {*,.[!.]*}.
G-Man

@ G-Man ขอโทษด้วย ดังนั้นคุณถูกต้องและไม่ดีของฉันไม่เห็นการตอบสนองของ ndemou พวกมันค่อนข้างเหมือนกัน 1. ขอบคุณสำหรับการชี้ให้เห็นว่ารุ่นของฉันไม่ได้เป็นไปตามมาตรฐาน posix 2. ฉันใช้วงเล็บปีกกาเพื่อสร้างรายการของสตริงที่เชลล์จะใช้เพื่อดำเนินการกับ นอกจากนี้ยังหมายความว่าฉันไม่จำเป็นต้องcdลงในไดเรกทอรีต้นทางเพื่อดำเนินการกับไฟล์หรือเขียนเส้นทางไฟล์เดียวกันซ้ำไปซ้ำมาเพื่อแสดงเส้นทางไปยังไฟล์ทั้งหมด ฉันจะอัปเดตตัวอย่างเร็ว ๆ นี้เพื่อให้ผู้อ่านทุกคนเห็นภาพที่ดีขึ้นเกี่ยวกับสิ่งที่ฉันกำลังพูดถึง
cmndr sp0ck

0

สำหรับdistros Linux ที่น้อยที่สุดสิ่งต่อไปนี้ควรใช้งานได้ ก่อนอื่นให้ทำการย้ายแบบพื้นฐานทั้งหมด (ซึ่งพลาดไฟล์ที่ซ่อนอยู่) จากนั้นย้ายไฟล์ที่ซ่อนอยู่ทั้งหมด (รวมถึง.และไฟล์..ใดที่จะไม่ถูกย้ายไปจริง)

mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null

หมายเหตุ:หากไม่มีเนื้อหาที่มองเห็นได้คำสั่งแรกจะสร้างข้อความแสดงข้อผิดพลาด คำสั่งที่สองจะเสมอผลิตข้อผิดพลาดบอกว่ามันไม่สามารถเคลื่อนย้ายและ. ..เช่นนี้เพียงวางข้อผิดพลาดลงใน/dev/null(ดังแสดง)

หากคุณต้องการสิ่งนี้ในแบบซับเดียวให้รวมเข้ากับเซมิโคลอน:

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