วิธีลบ (1) จากชื่อไฟล์โดยใช้คำสั่ง find


13

ฉันเพิ่งแปลงไฟล์ FLAC ทั้งหมดของฉันเป็นอัตราการสุ่มตัวอย่างที่ต่ำกว่า 44.1 kHz และความลึกบิต 24 บิต (เนื่องจาก iPhone / iPod ไม่รองรับสิ่งที่เหนือกว่า) โดยใช้ XLD บน Mac OS 10.7 (Lion)

แม้ว่าฉันจะบอกให้ XLD เขียนทับไฟล์ก่อนหน้านี้ทั้งหมด แต่ XLD ก็ต่อ(1)ท้ายไฟล์ที่คล้ายกันมาก

some_song.m4a

ถึง

some_song(1).m4a

ดังนั้นตอนนี้ฉันต้องการลบไฟล์นั้น(1)จากไฟล์ FLAC ทั้งหมดที่ฉันแปลง

ฉันรู้ว่าฉันอาจจะใช้บางโปรแกรมหรือแม้แต่ AppleScript เพื่อเปลี่ยนชื่อไฟล์ แต่ฉันต้องการเรียนรู้โดยใช้บรรทัดคำสั่งโรงเรียนเก่า

ฉันรู้ว่าfind . -name *\(1\).m4aจะคว้าไฟล์ FLAC ที่แปลงแล้วทั้งหมด

ต่อไปฉันรู้ว่าฉันต้องทำบางสิ่งด้วย-execและmvเปลี่ยนชื่อไฟล์ที่พบทั้งหมด (1)แต่สิ่งที่ผมไม่สามารถคิดออกเป็นวิธีที่จะทำให้ชื่อไฟล์เดิมและมีเพียงลบ

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

ยินดีต้อนรับเคล็ดลับหรือคำแนะนำ! ขอบคุณ!


5
ทำไมต้องลงคะแนน? ดูเหมือนว่าคำถามที่ถูกต้อง ...

ไม่เกี่ยวข้องกับคำถามเฉพาะของคุณ (บนfind) แต่นั่นอาจเป็นการแก้ปัญหาที่แท้จริงของคุณ (การแปลงไฟล์เสียง) คุณอาจสนใจที่จะดูaudiotools.sourceforge.netและตัวอย่างกรณีนี้ (สำหรับ macosx lion) invibe.net/ LaurentPerrinet / SciBlog / 2012-04-22
meduz

คำตอบ:


13

อย่าพยายามแยกวิเคราะห์findเอาต์พุตยกเว้นวิธีสุดท้าย สิ่งสำคัญคือต้องตระหนักว่าในระบบไฟล์ Unix ชื่อไฟล์ไม่ใช่สตริง (ความเข้าใจผิดทั่วไป) แต่เป็นblobs ไบนารีซึ่งสามารถมีอักขระใด ๆ ยกเว้น/และอักขระ null การแยกชื่อไฟล์อย่างปลอดภัยและถูกต้องนั้นเพียงพอสำหรับความเจ็บปวดที่ 99% ของเวลาที่คุณต้องการหลีกเลี่ยงการทำมันทั้งหมด (แค่ดูว่าการsedแสดงออกของขนในคำตอบของ @ yarekมีขนดกแค่ไหนและถึงแม้จะไม่ครอบคลุมทุกกรณี) . โชคดีที่ในกรณีนี้มีวิธีการที่ง่ายกว่ามาก:

find . -name '*(1).m4a' -execdir sh -c \
'for arg; do mv "$arg" "${arg%(1).m4a}".m4a; done' _ {} \+

วิธีที่เรียบร้อยยังมีขนดกตามการแสดงความรู้สึก :) +1
yrk

1
บางสิ่งบางอย่างที่ขาดหายไปที่นี่ ... ที่ของdone?
yrk

@ yarek ขอบคุณสำหรับการจับ ความแตกต่างที่ใหญ่ที่สุดระหว่างสิ่งนี้กับsedวิธีการไพพ์คือสิ่งนี้ปลอดภัยกว่ามาก ยังอ่านได้ง่ายกว่าเครื่องหมายแบ็กสแลชซุป regex ถ้าคุณเข้าใจการสร้างเชลล์สคริปต์พื้นฐาน
jw013

คุณถูก; นี้สะอาดกว่ามาก และ$argตัวแปรทำให้อ่านง่ายขึ้นมาก
hobbes3

1
@DQdlM ตัวอย่างที่ฉันโพสต์ด้านบนเป็นเพียงการfindเรียกใช้shด้วยไวยากรณ์ POSIX แบบพกพาค่อนข้าง สำหรับรายละเอียดเพิ่มเติมคุณสามารถตรวจสอบส่วนที่เกี่ยวกับการขยายตัวพารามิเตอร์ที่ส่วนที่เกี่ยวกับคำสั่งสารประกอบที่อธิบายforห่วงและPOSIXfindข้อมูลจำเพาะ นอกเหนือจากแหล่งข้อมูลเหล่านั้นฉันยินดีที่จะตอบคำถามเฉพาะที่คุณมี
jw013

6

บน Debian และ Ubuntu ฉันสามารถใช้rename 's/\(1\)//' *.m4aเพื่อแก้ปัญหาของคุณ


แปลกฉันทำได้man renameแต่จริง ๆ แล้วฉันไม่มีrename: -bash: rename: command not found( which renameไม่แสดงอะไรเลย)
hobbes3

@ hobbes3 บน mac ที่นี่man -a renameค้นหาการเปลี่ยนชื่อ (2) - syscall และเปลี่ยนชื่อ (n) - คำสั่ง TCL ไม่มีการเปลี่ยนชื่อ (1) หรือยูทิลิตี้เอง
yrk

1
IIRC renameเป็นสคริปต์ Perl ที่มาพร้อมกับตัวอย่างที่รวมอยู่ในการติดตั้ง Perl บางส่วนและ distros คู่รวมไว้ในพา ธ เนื่องจากเป็นคำสั่งที่สะดวก (@Hobbes บางทีคุณสามารถค้นหาได้ทางอินเทอร์เน็ต)
Kevin

@ เควินในระบบของฉันrenameเป็นไบนารีปกติ (ไม่ใช่ภาษา Perl) อย่างไรก็ตามข้อแม้อื่นคือไม่renameสนับสนุนทุกรุ่นregexes ยกตัวอย่างเช่นรุ่นที่ฉันมีให้คุณทำการแทนที่สตริงโดยตรงเช่นrename '(1)' '' *.m4a
Patrick

1
renameสคริปต์Perl นั้นถูกติดตั้งโดย Debian และอนุพันธ์เท่านั้น ระบบ Linux อื่นมีrenameยูทิลิตีอื่น (แสดงโดย Patrick) OSX ไม่มี
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

4

ใน zsh โดยใช้zmv :

autoload zmv      # you can put this line in your .zshrc
zmv '(*)\(1\)(*)' '$1$2'

ในอาร์กิวเมนต์ที่สอง (ชื่อใหม่) $1และ$2อ้างถึงกลุ่มวงเล็บ(PATTERN)ในรูปแบบของแหล่งที่มา อีกวิธีในการเขียนการเปลี่ยนชื่อนี้คือ

zmv '(*)' '${1/\(1\)/}'

3

วิธีการต่อไปนี้ให้ความสามารถในการดูตัวอย่าง / ตัดคำสั่งที่สร้างขึ้นก่อนที่จะดำเนินการและเป็นแบบพกพา: มันควรทำงานได้ไม่เพียง แต่ใน mac, ไม่เพียง แต่กับทุบตีและไม่เพียงกับ GNU sed; แม้ในระบบที่ไม่มีfindคำสั่ง (1) ก็เป็นไปได้ที่จะแทนที่ด้วยdu(1) โดยไม่มีปัญหา

find . -name '*(1).m4a' |
sed 's/\(.*\)(1).m4a$/mv & \1.m4a/' 

หากพอใจกับคำสั่งที่พิมพ์ออกมาให้เรียกใช้อีกครั้งด้วยการ| sh -xต่อท้าย

หากความกังวลเกี่ยวกับช่องว่างในชื่อไฟล์เพิ่มอีกsที่จะหลบหนีช่องว่างทั้งหมด:

find . -name '*(1).m4a' |
sed -e 's/ /\\ /g' -e 's/\(.*\)(1).m4a$/mv & \1.m4a/'

หากคาดว่าจะมีตัวอักษรพิเศษอื่น ๆ มันจะค่อนข้างยุ่งยากมากขึ้น:

find . -name '*(1).m4a' |
sed -e "s/'/'\\\\''/g" -e 's/\(.*\)(1).m4a$/mv '\''&'\'' '\''\1.m4a'\'/

ฟังก์ชั่นแรกจะแปลงทั้งหมด'ให้อยู่ในรูปแบบที่ว่าสิ่งเหล่านี้จะถูกนำไปใช้อย่างแท้จริงเมื่ออยู่ในช่วงกลางของ'...'สตริงที่มี Escape ฟังก์ชั่นที่สองสร้างmv'...'คำสั่งที่มีข้อโต้แย้งที่จะอยู่ภายใน


1
คำสั่งนั้นจะไม่หนีชื่อไฟล์ (ช่องว่าง(และอักขระพิเศษอื่น ๆ ทั้งหมด) หรือเพิ่มเครื่องหมายคำพูดรอบ ๆ ชื่อไฟล์ ฉันพยายามแก้ไขคำสั่งของคุณ แต่ฉันไม่สามารถหาวิธีเพิ่มเครื่องหมายคำพูดรอบทั้งชื่อไฟล์สำหรับmvคำสั่ง mv ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us(1).m4a ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us.m4aหนึ่งของการส่งออกที่เกิดจากคำสั่งของคุณ -bash: syntax error near unexpected token '('และถ้าผมเรียกใช้คำสั่งที่ฉันได้รับ
hobbes3

นี่น่าจะเป็นการบ้าน :) แต่โอเคฉันจะอัปเดตคำตอบ
yrk

โดยวิธีที่ GNU sed สามารถดำเนินการคำสั่งด้วยตนเองโดยการเพิ่มeคำสั่งหลังการทดแทน ยกตัวอย่างเช่นfind . -name '*(1).m4a' | sed 's/\(.*\)(1).m4a$/mv & \1.m4a/e'จะ exexcute sh -xคำสั่งโดยไม่ต้องท่อไป
เร่งงาน

@ เร่งด่วนนั่นเป็นสิ่งเดียวที่ทำได้ และจะต้องเริ่มต้นเปลือกแล้ว แต่หนึ่งใหม่สำหรับแต่ละคำสั่ง (เตือนแต่งหน้าของปัญหาไม่ได้หรือไม่)
yrk

2
ฉันไม่คิดว่าเราควรจะลงคะแนน มันเป็นทางออกที่ถูกต้องหลังจากทั้งหมด
hobbes3

1

นี่เป็นสคริปต์ขนาดเล็กที่ทำ:

for var in `find . -type f -name "*(1).m4a"`; do
    new=`echo $var | cut -d'(' -f1`;
    mv $var $new.m4a;
done

อันนี้จะทำให้หายใจไม่ออกในไฟล์ที่มีช่องว่างในชื่อของพวกเขา; นอกจากนี้ยังจะต้องมีการจัดเก็บชั่วคราวขนาดใหญ่พอสำหรับ`find ...`
yrk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.