Як видалити (1) з імен файлів за допомогою команди find


13

Нещодавно я перетворив усі мої FLAC-файли на меншу частоту дискретизації 44,1 кГц і глибину бітів 24 біт (оскільки iPhone / iPod нічого не підтримує вище) за допомогою XLD на моїй Mac OS 10.7 (Lion).

Хоча я наказав XLD перезаписати всі попередні файли, XLD додав a (1)в кінці самого файлу, як з

some_song.m4a

до

some_song(1).m4a

Тому тепер я хочу видалити це (1)з усіх файлів FLAC, які я перетворив.

Я знаю, що, можливо, я міг би використати якусь програму або навіть AppleScript для перейменування файлів, але я хотів навчитися використовувати старий шкільний спосіб командного рядка.

Я знаю, що find . -name *\(1\).m4aзахопить весь перетворений файл FLAC.

Далі я знаю, що мені щось робити -execі mvперейменувати всі знайдені файли. Але я не можу зрозуміти, як зберегти оригінальне ім'я файлу та лише видалити (1).

Можливо, мені потрібно зробити деякий груповий регекс із захопленням, щоб зберігати частину імені файлу, яку я не хочу змінювати? А може, неможливо зробити все в одному рядку, і я повинен створити сценарій оболонки (що мені не так зручно, але я готовий спробувати).

Будь-які поради та пропозиції вітаються! Спасибі!


5
Чому потік? Здається, це питання дійсне ...

не пов’язане з вашим конкретним питанням (увімкнено find), але це може вирішити вашу фактичну проблему (перетворення аудіофайлів), можливо, вам буде цікаво подивитися на audiotools.sourceforge.net та на цей приклад (для macosx лева) invibe.net/ LaurentPerrinet / SciBlog / 2012-04-22
meduz

Відповіді:


13

Не намагайтеся проаналізувати findвихід, окрім крайнього випадку. Важливо усвідомити, що в файлових системах Unix назви файлів - це не рядки (поширена помилкова думка), а скоріше двійкові краплі, які можуть містити будь-який символ, крім /і нульовий символ. Розбір імен файлів безпечно та правильно - це достатньо болю, що у 99% випадків ви просто хочете уникати цього взагалі (просто подивіться, наскільки волохатим є sedвираз у відповіді @ yarek і навіть, який охоплює не всі випадки) . На щастя, у цьому випадку існує набагато простіший підхід:

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

акуратний підхід, але такий же волохатий, як вираз sed:) +1
yrk

1
чогось тут не вистачає ... де done?
yrk

@yarek Дякую за улов. Найбільша різниця між цим і sedпідходом до труб - це набагато безпечніше. Це все-таки легше читати, ніж суп із зворотньо-косою рисою, якщо ви розумієте деякі основні конструктивні сценарії оболонки.
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, а rename (n) - команду TCL. Там немає ні перейменування (1), ні самої утиліти.
yrk

1
IIRC, renameце сценарій perl, включений із прикладами, включеними до деяких встановлень perl, і кілька дистрибутивів включають його в шлях, оскільки це зручна команда. (@Hobbes, можливо, ви можете знайти її в Інтернеті)
Кевін

@Kevin у моїй системі renameє нормальним бінарним (не перл). Однак ще одне застереження полягає в тому, що не всі версії renameпідтримують регулярні виразки. Наприклад, версія, яка у мене є, дозволяє лише робити прямі заміни рядків, наприкладrename '(1)' '' *.m4a
Патрік

1
renameСценарій Perl встановлюється лише Debian та похідними. Інші системи Linux мають іншу renameкорисність (показана Патріком). У OSX немає жодного.
Жил "ТАК - перестань бути злим"

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, не тільки з bash, а не тільки з GNU sed; навіть у системах без findкоманди du(1) можна без проблем замінити його на (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'\'/

Перша функція перетворює все 'в таку форму, що приймається буквально в середині '...'відміненого рядка. Друга функція генерує 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

це повинно бути домашнім завданням :), але добре, я
оновлю

До речі, GNU sed може виконувати команду самостійно, додаючи eкоманду після підстановки. Наприклад find . -name '*(1).m4a' | sed 's/\(.*\)(1).m4a$/mv & \1.m4a/e', виконуватиме команду exexcute без підключення до sh -x.
пік

@Rush - це єдиний сед, який робить це; і їй потрібно все-таки запустити оболонку, але нова для кожної команди (нагадує проблему make , чи не так?)
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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.