ฉันลืมระบุปลายทางโดยไม่ตั้งใจก่อนกดปุ่มย้อนกลับ ที่ไหนmv ./*
โดยไม่ระบุปลายทางย้ายไฟล์และไดเรกทอรีภายใต้ไดเรกทอรีปัจจุบันไป?
mv
ยอมรับการโต้แย้ง 1 ข้อ" ไม่เช่นนั้น *
มันรับทุกข้อโต้แย้งเปลือกผ่านไปหลังจากที่ขยาย
ฉันลืมระบุปลายทางโดยไม่ตั้งใจก่อนกดปุ่มย้อนกลับ ที่ไหนmv ./*
โดยไม่ระบุปลายทางย้ายไฟล์และไดเรกทอรีภายใต้ไดเรกทอรีปัจจุบันไป?
mv
ยอมรับการโต้แย้ง 1 ข้อ" ไม่เช่นนั้น *
มันรับทุกข้อโต้แย้งเปลือกผ่านไปหลังจากที่ขยาย
คำตอบ:
หากอาร์กิวเมนต์สุดท้ายเป็นไดเรกทอรีคุณเพียงแค่ย้ายไฟล์และไดเรกทอรีทั้งหมดในไดเรกทอรีการทำงานปัจจุบันของคุณ (ยกเว้นชื่อที่ขึ้นต้นด้วยจุด) ในไดเรกทอรีนั้น หากมีไฟล์สองไฟล์ไฟล์แรกอาจเขียนทับไฟล์ที่สอง
นี่คือการสาธิต:
มีมากกว่าสองไฟล์และอาร์กิวเมนต์สุดท้ายคือไฟล์
$ mkdir d1 d2 d3
$ touch a b c e
$ mv *
mv: target 'e' is not a directory
มีมากกว่าสองไฟล์และอาร์กิวเมนต์สุดท้ายคือไดเรกทอรี
$ mkdir d1 d2 d3
$ touch a b c
$ mv -v *
'a' -> 'd3/a'
'b' -> 'd3/b'
'c' -> 'd3/c'
'd1' -> 'd3/d1'
'd2' -> 'd3/d2'
สองไฟล์
$ touch a b
$ mv -v *
'a' -> 'b'
คำอธิบายเพิ่มเติม
เปลือกขยาย glob ( *
) mv
ลงในข้อโต้แย้ง glob มักจะขยายตามลำดับตัวอักษร mv
เห็นรายการของไฟล์และไดเรกทอรีเสมอ มันไม่เคยเห็นก้อนกลมตัวเอง
คำสั่งmv
รองรับการเคลื่อนที่สองประเภท mv file ... directory
หนึ่งในนั้นคือ อีกอันคือmv old-file-name new-file-name
(หรือmv old-file-name directory/new-file-name
)
ก่อนอื่นฉันจะสร้างฐานทดสอบ - 5 ไฟล์และหนึ่งโฟลเดอร์:
touch file1 file2 file3 file4 file5
mkdir folder
ต่อไปฉันจะเรียกใช้คำสั่งทดสอบ ระบุตัวเลือกที่ฉันต้องการคำสั่งรันเปลือกที่จะพิมพ์ทุก-v
ตัวเลือกระบุว่าฉันต้องการเดียวกันพิมพ์ไป- แต่ฉันต้องการจะทำหลังจากที่คำสั่งจะถูกประเมิน แต่ก่อนที่จะเปลือกมันวิ่งstderr
-x
stderr
sh -cxv 'echo mv *'
echo mv *
+ echo mv file1 file2 file3 file4 file5 folder
mv file1 file2 file3 file4 file5 folder
ดังนั้นคุณจะเห็นว่าคำสั่งที่ฉันป้อนเชลล์คือecho mv *
และคำสั่งที่เชลล์ดำเนินการหลังจาก *
ถูกขยายจะecho mv
ตามด้วยไฟล์และโฟลเดอร์เหล่านั้นทั้งหมด
โดยค่าเริ่มต้นเปลือกจะขยายglobsเช่น:
sh -cxv 'echo file[1-5]'
echo file[1-5]
+ echo file1 file2 file3 file4 file5
file1 file2 file3 file4 file5
นี่คือผลลัพธ์ของset [+-]f
ฟังก์ชัน glob:
sh -cxvf 'echo file[1-5]'
echo file[1-5]
+ echo 'file[1-5]'
file[1-5]
ดังนั้นเมื่อคุณรันคำสั่งในเชลล์ที่กำหนดค่าด้วยตัวเลือกเริ่มต้นเช่นmv *
เชลล์จะขยายเข้าไปใน*
คำว่ารายการอาร์กิวเมนต์ของไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันเรียงตามโลแคล มันเป็น syscall exec(ve)
สำหรับmv
(เป็นหลัก)กับรายการอาร์กิวเมนต์นี้ต่อท้าย ดังนั้นmv
ได้รับทั้งหมดของการขัดแย้งเป็นเปลือก globs พวกเขาและพวกเขาเรียงลำดับ นอกเหนือจากการทำstrace
เพื่อดูเอฟเฟกต์เหล่านี้คุณสามารถใช้ดีบั๊กได้อีกครั้งเช่น:
sh -s -- mv * <<\SCRIPT
sed -n l /proc/$$/cmdline
echo "$@"
SCRIPT
sh\000-s\000--\000mv\000file1\000file2\000file3\000file4\000file5\000folder\
\000$
mv file1 file2 file3 file4 file5 folder
และแบบพกพา:
( PS4= IFS=/; set -x mv *; : "/$*/" ) 2>&1
: /mv/file1/file2/file3/file4/file5/folder/
โดยทั่วไปเชลล์ดำเนินการmv
กับเนื้อหาของไดเรกทอรี(ถ้าไม่ว่างเปล่าและไม่รวมไฟล์ / โฟลเดอร์ที่มีชื่อขึ้นต้นด้วย.
)เป็นรายการอาร์กิวเมนต์ mv
เป็น POSIX ระบุการตีความอาร์กิวเมนต์สุดท้ายเป็นไดเรกทอรีถ้ามันถูกเรียกด้วยมากกว่าสองข้อโต้แย้ง - ในทางเดียวกันln
คือ(เพราะในความจริงพวกเขากำลังเครื่องมือที่คล้ายกันอย่างไม่น่าเชื่อในฟังก์ชั่นพื้นฐาน)
แต่เพียงพอแล้วecho
:
sh -cxv 'mv *' ; ls
mv *
+ mv file1 file2 file3 file4 file5 folder
folder/
ไฟล์ทั้งหมดถูกย้ายไปยังอาร์กิวเมนต์สุดท้าย - เนื่องจากเป็นโฟลเดอร์ ตอนนี้ถ้ามันไม่ใช่โฟลเดอร์ล่ะ?
sh -cxv 'cd *; mv *'; ls . *
cd *; mv *
+ cd folder
+ mv file1 file2 file3 file4 file5
mv: target ‘file5’ is not a directory
.:
folder/
folder:
file1 file2 file3 file4 file5
นี่คือวิธีที่POSIX ระบุว่า mv
ควรประพฤติตนอย่างไรในกรณีนั้น:
mv [-if] source_file target_file
mv [-if] source_file... target_dir
ในรูปแบบบทสรุปแรก,
mv
ยูทิลิตี้จะย้ายไฟล์ตั้งชื่อตามตัวถูกดำเนินการ source_file ไปยังปลายทางที่ระบุโดยtarget_file แบบฟอร์มสรุปครั้งแรกนี้จะถือว่าเมื่อตัวถูกดำเนินการขั้นสุดท้ายไม่ได้ตั้งชื่อไดเรกทอรีที่มีอยู่และไม่ได้เป็นลิงค์สัญลักษณ์ที่อ้างถึงไดเรกทอรีที่มีอยู่ ในกรณีนี้ถ้าsource_fileตั้งชื่อไฟล์ที่ไม่ใช่ไดเรกทอรีและtarget_fileลงท้ายด้วย/slash
อักขระต่อท้ายmv
จะถือว่าสิ่งนี้เป็นข้อผิดพลาดและไม่มีตัวถูกดำเนินการsource_fileจะถูกประมวลผลในรูปแบบสรุปที่สอง
mv
จะย้ายแต่ละไฟล์ที่ชื่อโดย source_file ตัวถูกดำเนินการไปยังไฟล์ปลายทางในไดเรกทอรีที่มีอยู่ชื่อโดยตัวถูกดำเนินการtarget_dirหรืออ้างอิงถ้าtarget_dirเป็นลิงค์สัญลักษณ์ที่อ้างอิงถึงไดเรกทอรีที่มีอยู่ เส้นทางปลายทางสำหรับแต่ละ source_file จะต้องเรียงต่อกันของไดเรกทอรีเป้าหมายเดียว/slash
ตัวละครถ้าเป้าหมายไม่ได้จบใน/slash
และองค์ประกอบชื่อพา ธ สุดท้ายของsource_file แบบฟอร์มที่สองนี้จะถือว่าเมื่อตัวถูกดำเนินการขั้นสุดท้ายตั้งชื่อไดเรกทอรีที่มีอยู่
ดังนั้นหาก*
ขยายไปที่:
สองไฟล์
renamed
unlinked
ไฟล์อย่างน้อยหนึ่งไฟล์ตามมาด้วยไดเรกทอรีหรือลิงค์ไปยังไฟล์ล่าสุด
สิ่งอื่นใด
sh
ฉันลืมเกี่ยวกับการแก้จุดบกพร่องด้วย แต่คำถามเดิมของฉันก็หมายความว่าปัญหาเปลือกไม่mv
? ช่างเป็นเรื่องที่น่ารังเกียจมันง่ายกว่าที่ข้าเคยคิดไว้ แต่มันเป็นกับดักที่แท้จริง
*
ไม่ใช่อาร์กิวเมนต์เดียวใช่ไหม ขวา? :)
ก่อนอื่นเชลล์จะขยาย./*
ไปยังไฟล์ทั้งหมดในไดเรกทอรีปัจจุบัน (ยกเว้นไฟล์ที่ขึ้นต้นด้วยจุด)
mv
ล้มเหลวmv
ล้มเหลวecho ./*
ดูว่าลำดับที่เชลล์ของคุณใช้ (ปกติคือตัวอักษร)
mv
ส่งกลับข้อผิดพลาดถ้ามันถูกเรียกว่ามีเพียงหนึ่งข้อโต้แย้ง
missing destination file operand after *filename*
แม้ว่าจะไม่ได้
เมื่อคุณพิมพ์mv ./*
, เปลือกของคุณจะขยายตัวก่อนที่จะดำเนิน./*
mv
สิ่งที่ควรทราบ:
./*
มีการขยายออกเป็นอาร์กิวเมนต์น้อยกว่า 2 ข้อmv
จะทำให้เกิดข้อผิดพลาดทางตรรกะ./*
โดยปกติจะขยายเป็นทุก ๆ ไฟล์ (รวมถึงไดเรกทอรี) ที่มีอยู่ในไดเรกทอรีปัจจุบันและไม่เริ่มต้นด้วยจุด./*
ขยายออกไปได้โดยอ่านเอกสารของเชลล์ของคุณ ( man 7 glob
เป็นจุดเริ่มต้นของหัวข้อ) กระสุนที่แตกต่างกันจะมีตัวเลือกต่างกันอะไร
mv *
ทำอย่างไร
นี่คือคำตอบที่สั้นกว่า:
เชลล์ขยาย wildcard *
เป็นรายการของเนื้อหาไดเร็กทอรี จากนั้นเชลล์จะส่งรายการทั้งหมดไปยังคำสั่ง *
คำสั่งที่ไม่เคยเห็น
คำสั่งmv file1 file2 ... filen directory
จะย้าย file1 ... filen ไปยังไดเรกทอรี
ที่นี่ฉันทำไดเรกทอรีทดสอบที่มีสามไฟล์
$ mkdir t
$ cd t
$ echo a>a; echo b>b; echo c>c
$ ls
a b c
คุณไม่สามารถย้ายไฟล์หลายไฟล์เป็นไฟล์เดียว
$ mv *
mv: target `c' is not a directory
ลองเพิ่มไดเรกทอรีย่อย
$ mkdir d
คุณสามารถย้ายไฟล์หลายไฟล์ไปไว้ในส่วนย่อยได้
$ mv *
$ ls
d
$ ls d
a b c
mv file1 file2 ... filen directory
มีโอกาสน้อยมากที่จะทำอะไรกับ*
มัน
*
เข้าไปfile dir
จนกว่าจะมีสถานที่บางส่วนดังนี้d
f
a b c d
ไม่ตรงfile ... dir
ไหน ฉันแสดงความคิดเห็นเพียงเพราะคุณไม่ได้พูดถึงการเรียงลำดับที่ใดก็ได้และพูดเฉพาะที่*
กลายเป็นfile ... dir
สิ่งที่ไม่เกิดขึ้น