ฉันต้องการเปลี่ยนชื่อไฟล์เพื่อเปลี่ยนนามสกุลไฟล์อย่างมีประสิทธิภาพ
mv *.txt *.tsv
แต่เมื่อทำสิ่งนี้ฉันจะได้รับ:
* .tsv ไม่ใช่ไดเรกทอรี
ฉันคิดว่ามันค่อนข้างแปลกที่การแสดง 10 google hits ครั้งแรกน่าmvจะเป็นแบบนี้
ฉันต้องการเปลี่ยนชื่อไฟล์เพื่อเปลี่ยนนามสกุลไฟล์อย่างมีประสิทธิภาพ
mv *.txt *.tsv
แต่เมื่อทำสิ่งนี้ฉันจะได้รับ:
* .tsv ไม่ใช่ไดเรกทอรี
ฉันคิดว่ามันค่อนข้างแปลกที่การแสดง 10 google hits ครั้งแรกน่าmvจะเป็นแบบนี้
คำตอบ:
เมื่อคุณใช้คำสั่ง:
mv *.txt *.tsv
เชลล์, ให้ถือว่า bash, ขยาย wildcards หากมีไฟล์ที่ตรงกัน (รวมถึงไดเร็กทอรี) mvรายชื่อของไฟล์จะถูกส่งผ่านไปยังโปรแกรมที่นี่ หากไม่พบไม้ขีดไฟรุ่นที่ยังไม่ขยายจะถูกส่งผ่าน
อีกครั้ง: เชลล์ขยายรูปแบบไม่ใช่โปรแกรม
ตัวอย่างมากมายอาจเป็นวิธีที่ดีที่สุดดังนั้นเราไปที่นี่:
$ ls
file1.txt file2.txt
$ mv *.txt *.tsv
ตอนนี้สิ่งที่เกิดขึ้นบนmvบรรทัดคือเชลล์ขยาย*.txtไปยังไฟล์ที่ตรงกัน เนื่องจากไม่มี*.tsvไฟล์ที่ไม่เปลี่ยนแปลง
mvคำสั่งที่เรียกว่ามีสองข้อโต้แย้งพิเศษ :
argc: จำนวนอาร์กิวเมนต์รวมถึงโปรแกรมargv: อาร์เรย์ของอาร์กิวเมนต์รวมถึงโปรแกรมเป็นรายการแรกในตัวอย่างข้างต้นที่จะเป็น:
argc = 4
argv[0] = mv
argv[1] = file1.txt
argv[2] = file2.txt
argv[3] = *.tsv
mvตรวจสอบโปรแกรมเพื่อดูว่าข้อโต้แย้งที่ผ่านมา*.tsvเป็นไดเรกทอรี โปรแกรมจะไม่สามารถทำงานต่อได้เนื่องจากไม่ได้ออกแบบมาเพื่อเชื่อมไฟล์เข้าด้วยกัน (โดยทั่วไปย้ายไฟล์ทั้งหมดไปไว้ในที่เดียว) หรือสร้างไดเรกทอรีในสิ่งที่ต้องการ
ด้วยเหตุนี้จึงยกเลิกและรายงานข้อผิดพลาด:
mv: target ‘*.tsv’ is not a directory
ตอนนี้ถ้าคุณพูดว่า:
$ mv *1.txt *.tsv
mvคำสั่งจะถูกดำเนินการด้วย:
argc = 3
argv[0] = mv
argv[1] = file1.txt
argv[2] = *.tsv
ตอนนี้อีกครั้งmvตรวจสอบเพื่อดูว่า*.tsvมีอยู่ ในขณะที่มันไม่ได้ไฟล์จะถูกย้ายไปfile1.txt *.tsvนั่นคือ: ไฟล์ถูกเปลี่ยนชื่อ*.tsvด้วยเครื่องหมายดอกจันและทั้งหมด
$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’
$ ls
file2.txt *.tsv
ถ้าคุณพูดว่า:
$ mkdir *.tsv
$ mv *.txt *.tsv
mvคำสั่งจะถูกดำเนินการด้วย:
argc = 3
argv[0] = mv
argv[1] = file1.txt
argv[1] = file2.txt
argv[2] = *.tsv
เนื่องจาก*.tsvตอนนี้เป็นไดเรกทอรีไฟล์จะถูกย้ายไปที่นั่น
ตอนนี้: การใช้คำสั่งเช่นsome_command *.tsvเมื่อเจตนาคือการเก็บไวลด์การ์ดไว้ควรอ้างอิง โดยการอ้างอิงคุณป้องกันไม่ให้สัญลักษณ์ตัวแทนขยายถ้าควรมีการแข่งขันใด ๆ mkdir "*.tsv"เช่นการพูด
การขยายสามารถดูเพิ่มเติมได้ถ้าคุณทำเช่น:
$ ls
file1.txt file2.txt
$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists
ตอนนี้: mvคำสั่งสามารถทำงานหลายไฟล์ได้ แต่หากมีมากกว่าสองรายการสุดท้ายจะต้องมีไดเรกทอรีเป้าหมาย (เป็นทางเลือกคุณสามารถใช้-t TARGET_DIRตัวเลือกอย่างน้อย GNU mv)
ดังนั้นนี่คือตกลง:
$ ls -F
b1.tsv b2.tsv f1.txt f2.txt f3.txt foo/
$ mv *.txt *.tsv foo
นี่mvจะถูกเรียกด้วย:
argc = 7
argv[0] = mv
argv[1] = b1.tsv
argv[2] = b2.tsv
argv[3] = f1.txt
argv[4] = f2.txt
argv[5] = f3.txt
argv[6] = foo
fooและไฟล์ทั้งหมดจะจบลงในไดเรกทอรี
สำหรับลิงค์ของคุณ คุณได้ให้หนึ่ง (ในความคิดเห็น) ที่mvไม่ได้กล่าวถึงที่ทั้งหมด renameแต่ หากคุณมีลิงก์เพิ่มเติมคุณสามารถแชร์ได้ เช่นเดียวกับหน้าคนที่คุณอ้างว่าเป็นแบบนี้
ฉันรู้ว่านี่ไม่ได้ตอบคำถามของคุณ แต่ในกรณีที่คุณกำลังมองหาวิธีอื่นในการเปลี่ยนชื่อไฟล์เมื่อเทียบกับการวนรอบการทำงานของคุณทำไมไม่ใช้find? ฉันใช้คำสั่งนี้หลายครั้งเพื่อแทนที่นามสกุลไฟล์ในไดเรกทอรีขนาดใหญ่ด้วยไฟล์นับแสนไฟล์ สิ่งนี้ควรใช้กับระบบที่สอดคล้องกับ POSIX:
find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;
การแบ่งคำสั่ง:
'
.' => เส้นทางการค้นหาเริ่มต้นที่ไดเรกทอรีปัจจุบันที่มีเครื่องหมาย ' '
-name=> ตั้งชื่อการค้นหาที่ตรงกัน (ในกรณีนี้ไฟล์ทั้งหมดที่ลงท้ายด้วย.gappedPeak)
-exec=> ดำเนินการคำสั่งต่อไปนี้ในทุกการแข่งขัน
sh -c=> 'exec' สร้างสภาพแวดล้อมเชลล์อิสระสำหรับการแข่งขันแต่ละครั้ง
mv "$1" "${1%.gappedPeak}.bed"=>mvตัวแปรแรก (แสดงโดย$ 1 ) ซึ่งเป็นชื่อไฟล์ปัจจุบันเป็นชื่อใหม่ ที่นี่ฉันจับคู่สตริงย่อยและลบ; ลองใช้ var ก่อนอีกครั้ง$ 1และใช้%เพื่อลบออก.gappedPeakจากสตริง.bedที่สิ้นสุดเพียงแค่เชื่อมตัวแปรที่เหลืออยู่ซึ่งขณะนี้เป็นเพียงที่มีการสร้างใหม่ชื่อไฟล์test#.bedtest#.bedขีดล่างเป็นตัวยึดราคา$ 0
{}จะถูกแทนที่ด้วยแต่ละ (*.gappedPeak) ชื่อไฟล์ที่พบโดยfindคำสั่งและจะกลายเป็น$ 1กับshคำสั่ง
\;ทำเครื่องหมายจุดสิ้นสุดของ-execคำสั่ง นอกจากนี้คุณยังสามารถใช้หรือ';'";"
ตัวอย่าง:
[user@before]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak
[user@after]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed
file.abc-> blub.xyzในหลาย ๆ dirs:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
mv *.txt *.tsvไม่ทำงาน mvสามารถเปลี่ยนชื่อได้ครั้งละหนึ่งไฟล์เท่านั้น คุณเข้าใจผิดทั้งคำอธิบายหรือพวกเขาผิด
mmvและrenameสามารถเปลี่ยนชื่อหลายไฟล์พร้อมกัน แต่มีประมาณสองรุ่นrenameซึ่งเรียกว่าแตกต่างกัน ควรมีคำถามมากมายเกี่ยวกับที่นี่
rename mv
mv *.txt *.tsv mvไม่ (โดยปกติ) ไม่เห็น*.txtหรือ*.tsvแต่ชื่อไฟล์ที่ขยายด้วยเชลล์ จำนวนไฟล์อักขระตัวแทนเหล่านี้จะขยายเป็น "สุ่ม" สถานการณ์เดียวที่ทำงานนี้คือถ้ามีไฟล์ที่มีชื่อ*.txtซึ่งจะถูกเปลี่ยนชื่อเป็น (แท้จริง) *.tsv(โดยไม่ต้องอ้างอิงbashตัวเลือกnullglobจะต้องไม่ถูกตั้งค่า)
foo.txtและหนึ่งชื่อจะเขียนทับที่มีอยู่ไฟล์ ...baz.tsvmv *.txt *.tsv.tsv
ตัวอย่างเช่นถ้าคุณมีasd.txtและqwe.txtไฟล์ในไดเรกทอรีเมื่อคุณเรียกใช้คำสั่งมันพยายามที่จะย้ายทั้งสองไฟล์ลงในไดเรกทอรีที่ชื่อว่าmv *.txt *.tsv *.tsvเนื่องจากไม่มีไดเรกทอรีดังกล่าวจึงทำให้เกิดข้อผิดพลาด
rename(1)renameเป็นสคริปต์ Perl โดย Larry Wall ผู้สร้าง perl มันใช้เวลา regex Perl และดำเนินการกับชื่อไฟล์
rename 's/\.txt$/.tsv/' *.txt
หากคุณต้องการติดตั้งrenameบน Debian / Ubuntu คุณสามารถทำได้
sudo apt install rename
ตัวเลือกอื่นที่ควรพิจารณาคือการใช้:
cp -p *.txt *.tsv
rm -f *.txt
*.txtไฟล์ทั้งหมดไป*.tsvที่ในขณะที่รักษาคุณลักษณะของพวกเขาโดยใช้-pธง*.txtmvที่จะเปลี่ยน / directory / filename โดยไม่ต้องย้ายไฟล์ยกเว้นว่าอยู่ในพาร์ติชั่นอื่น