แทนที่โคลอนทั้งหมดจากชื่อไฟล์ด้วยเทอร์มินัล


12

ฉันมีค่า GB ของเพลงบน HDD ที่ฟอร์แมตด้วย EXT4 ฉันต้องการย้ายไฟล์เหล่านี้ไปยังพาร์ติชัน HDD ที่ฟอร์แมตด้วย FAT อย่างไรก็ตามฉันไม่สามารถย้ายไฟล์ส่วนใหญ่เนื่องจากมี ":" ในชื่อ (ตัวอย่างเช่น "Act 2: ..... " สำหรับโอเปร่า) มีวิธีที่บรรทัดคำสั่งเพื่อเปลี่ยนชื่อไฟล์ทั้งหมดของฉันจาก "XXXX: XXXX" เป็น "XXXX-XXXX" หรือไม่?

คำตอบ:


25

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

rename 's|:|-|g' *

(โดยที่ * สามารถเปลี่ยนเป็นสิ่งที่ จำกัด มากขึ้นหากคุณต้องการ)

หากคุณมีไฟล์จำนวนมากในแผนผังไดเรกทอรีให้ลองจากฐานของต้นไม้:

find . -name "*:*" -exec rename 's|:|-|g' {} \;

คุณสามารถเพิ่มตัวเลือกได้-nทันทีหลังจากrenameให้มันบอกคุณว่ามันจะทำอะไรโดยไม่ทำอย่างนั้นจริง ๆ สิ่งนี้อาจช่วยให้คุณหลีกเลี่ยงการเหยียบไฟล์อื่น ๆ โดยไม่ตั้งใจหรืออย่างอื่นไม่ดี ...


1
วิธีการแก้ปัญหาไดเรกทอรีเดียวจะทำงาน แต่การแก้ปัญหาที่ซ้อนกันจะไม่หากไดเรกทอรีตัวเองมี: s ในชื่อของพวกเขา นี่เป็นเพราะในผลลัพธ์ของfind .ชื่อของไดเรกทอรีย่อยนำหน้าเนื้อหา ดังนั้นถ้าคุณมีไฟล์/1:/2:แรกจะเปลี่ยนชื่อเป็น/1:/ /1-/ตอนนี้คุณไม่สามารถเปลี่ยนชื่อ/1:/2:เป็น/1-/2-เพราะ/1:/2:ไม่มีอยู่
S Prasanth

1
สำหรับไดเรกทอรี: find . -type d -readable -writable -exec rename 's|:|-|g' {} \;แล้วไฟล์:find . -type f -readable -writable -exec rename 's|:|-|g' {} \;

@Christopher คำสั่งสำหรับไดเรกทอรีจะล้มเหลวหากมีสองระดับของไดเรกทอรีด้วย: ในชื่อของพวกเขา เช่น: / 1: / 2: / โดยที่ 2: ยังเป็นไดเรกทอรี แน่นอนถ้าไม่ใช่ในกรณีของ Ryan สิ่งนี้จะใช้ได้
S Prasanth

สำหรับ sub-dirs หลายระดับให้ใช้: for i in {1..20}; do find . -maxdepth $i -mindepth $i -name "*:*" -exec rename 's|:|-|g' {} \;; done. เปลี่ยน 20 เป็นความลึกสูงสุดของ dir โครงสร้าง. ไม่ต้องแน่นอน - สามารถใหญ่ขึ้นได้ จะใช้เวลาถ้าตั้งไว้เป็นจำนวนมากแม้ว่า
S Prasanth

0

ฉันไม่ได้อยู่ที่เครื่อง linux ของฉันในตอนนี้ดังนั้นฉันสามารถให้ข้อมูลคร่าวๆ

ลีนุกซ์มียูทิลิตี commandline ชื่อrenameซึ่งทำงานได้กับอินพุตอื่น, นิพจน์ทั่วไปหรือ regexes คุณควรจะสามารถใช้สิ่งนั้นพร้อมกับ regex เช่น "s /: / - /" ในไฟล์ของคุณเพื่อให้ได้การเปลี่ยนชื่อที่คุณต้องการ

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


0

นี่คือวิธีการแก้ปัญหาในหลามซึ่งจัดการกรณีที่ไฟล์ไม่จำเป็นต้องอยู่ในไดเรกทอรีเดียวกัน

import os
torename = []
rootdir = "The main directory"
logfile = "Path to log file" #Eg: logfile = "/home/prasanth/renamelog"
for (path, dirs, files) in os.walk(rootdir):
    for dirname in dirs:
        if ':' in dirname:
            torename.append(os.path.join(path, dirname))
    for filename in files:
        if ':' in filename:
            torename.append(os.path.join(path, filename))

print "No of files/dirs to rename =", len(torename)
a = raw_input("Continue? (y/n) ")
if a == 'y':
    torename.reverse()
    for oldname in torename:
        directory, filename = os.path.split(oldname)
        newname = os.path.join(directory, filename.replace(':', '-'))
        command = 'mv %s %s > /dev/null' % (repr(oldname), repr(newname))
        os.system(command)
        f = open(logfile, 'a')
        f.write(oldname + '\n')
        f.close()
else:
    print "Aborted."
  1. บันทึกสิ่งนี้เป็นไฟล์ (พูด) rename.py
  2. เปลี่ยนrootdirเป็นไดเร็กทอรี outermost ภายใต้ข้อควรพิจารณา (ใช้ชื่อพา ธ แบบสมบูรณ์เริ่มต้นด้วย / ไม่มีตัวแปรชวเลขหรือ env เช่น ~ อนุญาต) ไม่จำเป็นต้องใส่ \ ก่อนอักขระพิเศษ - ตัวอย่างเช่นถ้า dir ด้านนอกสุดคือ /.../My HDD ของฉันใส่rootdir = "/.../My HDD"NOT rootdir = "/.../My\ HDD"(หมายเหตุ "s) [ฉันเป็นคนชัดเจนเพราะคุณอาจไม่คุ้นเคยกับงูหลาม ตั้งใจ.]
  3. เปลี่ยนlogfileเป็นตำแหน่งที่ต้องการของ logfile ในท้ายที่สุดไฟล์นี้จะมีรายการไฟล์ที่เปลี่ยนชื่อ - สำหรับการอ้างอิงในอนาคต
  4. โทรpython rename.py.

คำเตือน: อย่าทดสอบกับตัวอย่างเล็ก ๆ ก่อนที่จะเสี่ยงกับเพลงทั้งหมด GB

รายละเอียด: การเปลี่ยนชื่อจะดำเนินการจากไฟล์ด้านในสุดด้านนอก


0

ฉันรู้ว่านี่เป็นโพสต์เก่ามาก โซลูชันแบบเรียกซ้ำ AeroGT80 นั้นละเอียดมาก แต่ก็ค่อนข้างช้า ฉันให้มันทำงานประมาณครึ่งชั่วโมงบนเซิร์ฟเวอร์ที่ช้ากว่าและทำได้เพียงครึ่งเดียว - ฉันคิดว่าไฟล์นี้มีประมาณ 73,000 ไฟล์ในไดเรกทอรีย่อยประมาณ 300 รายการ

โซลูชันด้านล่างจะทำงานได้เร็วกว่ามาก (ทำงานกับไฟล์ทั้งหมดในไดเรกทอรีแทนแต่ละไฟล์ทีละไฟล์ - โดยใช้โซลูชันที่ไม่เรียกซ้ำของ AeroGT80) ปัญหาเดียวก็คือมันจะลงหนึ่งไดเรกทอรีลึก (ดังนั้นจึงไม่ recursive อย่างที่เขาเป็น) แต่ฉันแน่ใจว่ามันสามารถแก้ไขได้ง่ายพอ

#!/bin/bash
for D in *; do
        if [ -d "${D}" ]; then
                #echo "${D}"
                pushd "${D}" > /dev/null
                rename 's|:|-|g' *
                popd > /dev/null
        fi
done
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.