Потребовалось заменить кусок имени файла во всех файлах
рекурсивно в директории. Намучавшись с файлами в имени
которых есть пробелы и спец символы, я сдался и в целях
экономии времени написал на том на чем смог. Теперь в целях
повышения образованности мне интересно узнать как это
правильно сделать с помощью bash, sed, mv, и возможно find. Для файлов без пробелов на bash я написал. С пробелами не справился и написал это:
import org.apache.commons.io.*;
import java.util.*;
import java.util.regex.*;
import java.io.*;
public class Replace {
public static void main(String[] args) {
List<File> files = (List) FileUtils.listFiles(new File("/home/zort/something"), null, true);
Pattern p = Pattern.compile("old");
for (File a : files) {
Matcher m = p.matcher(a.toString());
String asdf = m.replaceAll("new");
a.renameTo(new File(asdf));
System.out.println(asdf);
}
}
}
просветите меня.
ЗЫ знаю что ламер - у меня на капитальное изучение баша
времени не нашлось.
> т.е. твой скрипт универсален ? для всеx допустимых в линуксе имен файлов ?
Хехе, нет, не универсален.
[tmp]> touch 'q
> w'
[tmp]> ls
q?w
[tmp]> ../rename.sh w d .
mv: невозможно выполнить stat для `./q': Нет такого файла или каталога
mv: невозможно выполнить stat для `w': Нет такого файла или каталога
[tmp]> ls
q?w
:)
perl от sdio работает
> perl от sdio работает
Упс, нет, тоже не работает.
[tmp]> ls -1
q?w
[tmp]> ls -1 | perl -ne 'chomp; $from="$_"; rename "$from", "$_" if (s/w/e/);'
[tmp]> ls -1
q?w
если честно, я действительно не знал как надо делать, и мне действительно было нужно, и я действительно сначала хотел это сделать юниксовым методом, чтобы так сказать знать врага в лицо, и просто уметь. а провоцировать я уже решил потом. честно.
дав ссылки, я раскрыл карты для тех кто тот флейм про слик не читал. потому что те кто мне помогали IMHO должны знать о моём отношении ко всему этому, и возможно показать где я ошибаюсь.
спорить не буду,от-части я создавал этот пост, для того чтобы быть увереным, что ругаю u-way не зря.
вабще то мои имена файлов показывают, что для того что бы выполнить эту операцию, нужно писать дополнительный код(пусть даже и коротрий как в случае у jini) который к этой операции отношения не имеет, а перекрывает проблему ескейпинг спецсимволов.
а то что я безграмотый в bash,я и отрицать не буду.
к тому же, я надеюсь никто спорить не будет, что ответ на этот вопрос на баше, не только для меня полезен будет,но и тем кто случайно сюда зашел. думаю не у меня одного такие проблемы возникают.
ну тогда получается что баша хватает только на запуск программ, всё остальное дешевле на питоне и перле. уж работать с любыми файлами баш должен уметь. нужен какой то главный, поддерживаемый всеми стандартными программами способ искейпинга имен файлов ....
перл это соединение модулей внутри пространства языка, а u-w это через пайпы в разных процессах, поэтому перл совместим с u-w настолько насколько умеет читать/писать stdin/out. никто не будет конектить перл с перлом через пайп.
если я не буду повторяться , то u-w фрики(т.е те кто кричит 'u-w это наше всё') будут себя воспроизводить дальше.
а повторяться мне действительно надоело, но здесь продолжают советовать bash sed awk, даже там где они на самом деле не уместны.
sun-ch мне даже один раз посоветовал bashем и awk выполнять чисто гуйную задачу по расфасовке файлпомойки - ещё одна распатроненная проблема - отрицание гуйни, мышки ,и дреэг энд дропа.
Вот же блин, такой флейм пропустил, а ведь моя любимая тема. :) Короче говоря, твой вариант на жабе тоже неправильный, так как он паттерн и в именах поддиректорий найдёт и попытается переименовать. А вообще ничего плохого в жабе я тут не вижу, раз она тебе привычнее. шеллы при работе с именами файлов всё же традиционно рассчитаны на то, что эти имена хорошие, тут ничего особенно не сделаешь. Я бы это на перле написал, с File::Find или find -print0 и уже чтением из перла.
Например так:
find dir -type f -print0 |./rename.pl, где rename.pl щас запощу.
Что касается unix way, то он не заключается в том, чтобы использовать менее подходящие для конкретной задачи инструменты, чем более подходящие. :)
#!/usr/bin/perl -w
use strict;
$/="\0";
while(<>) {
chomp;
next unless -f $_;
# s|/$||;
die "bad input" unless m|^(.+)/([^/]+)$|;
my ($dirname, $fname) = ($1, $2);
my $newfname = $fname;
$newfname =~ s/w/q/g;
next if $newfname eq $fname;
rename "$dirname/$fname", "$dirname/$newfname"
or die "can't rename [$fname] to [$newfname] in [$dirname]";
}
а вообще в состав перла входит скриптик rename, с ним делается примерно так (не проверял, просто ман прочитал): find . -print0 |xargs -0 rename 's/q/w/g'
проще вроде бы некуда, и должен корректно отработать для любых имён.