ฉันต้องการเปลี่ยนชื่อไฟล์เพื่อเปลี่ยนนามสกุลไฟล์อย่างมีประสิทธิภาพ
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#
.bed
test#.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.tsv
mv *.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
ธง*.txt
mv
ที่จะเปลี่ยน / directory / filename โดยไม่ต้องย้ายไฟล์ยกเว้นว่าอยู่ในพาร์ติชั่นอื่น