เปลี่ยนชื่อหลายไฟล์ด้วย mv เพื่อเปลี่ยนนามสกุล


27

ฉันต้องการเปลี่ยนชื่อไฟล์เพื่อเปลี่ยนนามสกุลไฟล์อย่างมีประสิทธิภาพ

mv *.txt *.tsv

แต่เมื่อทำสิ่งนี้ฉันจะได้รับ:

* .tsv ไม่ใช่ไดเรกทอรี

ฉันคิดว่ามันค่อนข้างแปลกที่การแสดง 10 google hits ครั้งแรกน่าmvจะเป็นแบบนี้


คุณควรอธิบายว่าคุณต้องการเปลี่ยนชื่อไฟล์เหล่านั้นอย่างไร
Totor

1
ฉันมีไฟล์ที่มีนามสกุล * .gappedPeak และต้องการเปลี่ยนชื่อไฟล์เป็น * .bed พวกเขาทั้งหมดในไดเรกทอรีเดียวกันมันควรจะง่ายมาก แต่เต็มไปด้วยการวนซ้ำเป็นสิ่งจำเป็นสำหรับฉันที่จะประสบความสำเร็จ
Sander Van der Zeeuw

สิ่งที่คุณพบใน Google ใช้กับ MSDOS ฉันคิดว่า
tiktak

โซลูชันสำรองของ @devnull มีประโยชน์จริงๆ
lucasvw

คำตอบ:


22

เมื่อคุณใช้คำสั่ง:

mv *.txt *.tsv

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

อีกครั้ง: เชลล์ขยายรูปแบบไม่ใช่โปรแกรม


ตัวอย่างมากมายอาจเป็นวิธีที่ดีที่สุดดังนั้นเราไปที่นี่:

ตัวอย่างที่ 1:

$ 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

ตัวอย่างที่ 2:

ตอนนี้ถ้าคุณพูดว่า:

$ 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

ตัวอย่างที่ 3:

ถ้าคุณพูดว่า:

$ 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"เช่นการพูด

ตัวอย่างที่ 4:

การขยายสามารถดูเพิ่มเติมได้ถ้าคุณทำเช่น:

$ ls
file1.txt file2.txt

$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists

ตัวอย่างที่ 5:

ตอนนี้: 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แต่ หากคุณมีลิงก์เพิ่มเติมคุณสามารถแชร์ได้ เช่นเดียวกับหน้าคนที่คุณอ้างว่าเป็นแบบนี้


30

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

find . -name "*.gappedPeak" -exec sh -c 'mv "$1" "${1%.gappedPeak}.bed"' _ {} \;

การแบ่งคำสั่ง:

  1. ' .' => เส้นทางการค้นหาเริ่มต้นที่ไดเรกทอรีปัจจุบันที่มีเครื่องหมาย ' '

  2. -name=> ตั้งชื่อการค้นหาที่ตรงกัน (ในกรณีนี้ไฟล์ทั้งหมดที่ลงท้ายด้วย .gappedPeak)

  3. -exec => ดำเนินการคำสั่งต่อไปนี้ในทุกการแข่งขัน

  4. sh -c => 'exec' สร้างสภาพแวดล้อมเชลล์อิสระสำหรับการแข่งขันแต่ละครั้ง

  5. mv "$1" "${1%.gappedPeak}.bed"=> mvตัวแปรแรก (แสดงโดย$ 1 ) ซึ่งเป็นชื่อไฟล์ปัจจุบันเป็นชื่อใหม่ ที่นี่ฉันจับคู่สตริงย่อยและลบ; ลองใช้ var ก่อนอีกครั้ง$ 1และใช้%เพื่อลบออก.gappedPeakจากสตริง .bedที่สิ้นสุดเพียงแค่เชื่อมตัวแปรที่เหลืออยู่ซึ่งขณะนี้เป็นเพียงที่มีการสร้างใหม่ชื่อไฟล์test#.bedtest#.bed

  6. ขีดล่างเป็นตัวยึดราคา$ 0

  7. {}จะถูกแทนที่ด้วยแต่ละ ( *.gappedPeak) ชื่อไฟล์ที่พบโดยfindคำสั่งและจะกลายเป็น$ 1กับshคำสั่ง

  8. \;ทำเครื่องหมายจุดสิ้นสุดของ-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

คุณช่วยอธิบายคำสั่งของแต่ละส่วนได้อย่างไร
user1717828

ฉันขอโทษที่ฉันอัปเดตโพสต์ของฉัน หวังว่าจะช่วย
devnull

1
เยี่ยมมากขอบคุณ! ด้วยคำแนะนำทุบตีและคำอธิบายของคุณฉันสามารถรับทุกสิ่งได้
user1717828

ไม่มีปัญหา. ดีใจที่ได้ช่วย
devnull

ทำงานเหมือนจับใจ นี่เป็นอีกตัวอย่างที่ง่ายสำหรับfile.abc-> blub.xyzในหลาย ๆ dirs:find . -name "file.abc" -exec sh -c 'mv "$1" "$(dirname $1)/blub.xyz"' _ {} \;
มาห์

9

mv *.txt *.tsvไม่ทำงาน mvสามารถเปลี่ยนชื่อได้ครั้งละหนึ่งไฟล์เท่านั้น คุณเข้าใจผิดทั้งคำอธิบายหรือพวกเขาผิด

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


1
cyberciti.biz/tips/ ......การโจมตีครั้งแรกบน google กำลังบอกว่า mv ควรจะทำงานได้เช่นกันทำไมฉันจึงพบว่ามันแปลกมาก
Sander Van der Zeeuw

3
@SanderVanderZeeuw ฉันไม่ทราบว่าคุณอ่านที่นั่น ตัวอย่างที่ใช้ไม่ได้rename mv
Hauke ​​Laging

1
ขอโทษฉันวางผิด HTML นี่คือudemy.com/blog/rename-a-file-in-linux
Sander Van der Zeeuw

3
@SanderVanderZeeuw น่าอาย คนเหล่านี้เสนอหลักสูตรหรือไม่ น่าเสียดายที่ฉันไม่เห็นโอกาสในการติดต่อที่นั่น คุณสามารถตรวจสอบว่ามันใช้งานได้ง่าย แต่ในmv *.txt *.tsv mvไม่ (โดยปกติ) ไม่เห็น*.txtหรือ*.tsvแต่ชื่อไฟล์ที่ขยายด้วยเชลล์ จำนวนไฟล์อักขระตัวแทนเหล่านี้จะขยายเป็น "สุ่ม" สถานการณ์เดียวที่ทำงานนี้คือถ้ามีไฟล์ที่มีชื่อ*.txtซึ่งจะถูกเปลี่ยนชื่อเป็น (แท้จริง) *.tsv(โดยไม่ต้องอ้างอิงbashตัวเลือกnullglobจะต้องไม่ถูกตั้งค่า)
Hauke ​​Laging

1
หรือแย่กว่านั้น หากหนึ่งมีหนึ่งแฟ้มที่ชื่อเช่นfoo.txtและหนึ่งชื่อจะเขียนทับที่มีอยู่ไฟล์ ...baz.tsvmv *.txt *.tsv.tsv
Runium

4

ตัวอย่างเช่นถ้าคุณมีasd.txtและqwe.txtไฟล์ในไดเรกทอรีเมื่อคุณเรียกใช้คำสั่งมันพยายามที่จะย้ายทั้งสองไฟล์ลงในไดเรกทอรีที่ชื่อว่าmv *.txt *.tsv *.tsvเนื่องจากไม่มีไดเรกทอรีดังกล่าวจึงทำให้เกิดข้อผิดพลาด


ขอบคุณสิ่งนี้ชัดเจนบางส่วน ฉันยังพบว่ามันแปลกที่ฉันเห็นหน้าคู่มือมากมายที่พวกเขาอ้างว่า mv ควรทำงานหลาย ๆ
Sander Van der Zeeuw

2

rename(1)

renameเป็นสคริปต์ Perl โดย Larry Wall ผู้สร้าง perl มันใช้เวลา regex Perl และดำเนินการกับชื่อไฟล์

rename 's/\.txt$/.tsv/' *.txt

การติดตั้ง

Debian / Ubuntu

หากคุณต้องการติดตั้งrenameบน Debian / Ubuntu คุณสามารถทำได้

sudo apt install rename

0

ตัวเลือกอื่นที่ควรพิจารณาคือการใช้:

cp -p *.txt *.tsv
rm -f *.txt
  • บรรทัดแรกคัดลอก*.txtไฟล์ทั้งหมดไป*.tsvที่ในขณะที่รักษาคุณลักษณะของพวกเขาโดยใช้-pธง
  • บรรทัดที่สองจะลบไฟล์ทั้งหมดที่มีรูปแบบ *.txt
  • วิธีนี้ต้องการให้คุณมีพื้นที่ดิสก์เพียงพอที่จะเก็บทั้งไฟล์ต้นทางและไฟล์เป้าหมายไว้ชั่วคราว
  • วิธีนี้ช้ากว่าmvที่จะเปลี่ยน / directory / filename โดยไม่ต้องย้ายไฟล์ยกเว้นว่าอยู่ในพาร์ติชั่นอื่น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.