LINUX.ORG.RU

Помогите со скриптом


0

0

Потребовалось заменить кусок имени файла во всех файлах 
рекурсивно в директории. Намучавшись с файлами в имени 
которых есть пробелы и спец символы, я сдался и в целях 
экономии времени написал на том на чем смог. Теперь в целях 
повышения образованности мне интересно узнать как это 
правильно сделать с помощью 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);
        }
    }
}

просветите меня.

ЗЫ знаю что ламер - у меня на капитальное изучение баша 
времени не нашлось.

Ответ на: комментарий от svu

я много чего пробовал, xargs точно, даже с -0 ключем и -print0 у файнда, но теперь хочу посмотреть на рабочий скрипт. ;)

zort
() автор топика
Ответ на: комментарий от svu

если подскажешь как после exec иди xargs аргумент разделить на переменные, и одну из неих отsedить, а потом передать мv, то я попробую. делать "man комманда" я умею, я в самом баше не разбираюсь.

zort
() автор топика
Ответ на: комментарий от zort

Грязный хак, но в большенстве случаев работает :)

#!/bin/bash
for FILE_NAME in $(find . -type f | sed 's/ /SpAcE/g')
do
    OLD_NAME=$(echo $FILE_NAME | sed s'/SpAcE/\ /g')
    NEW_NAME=$(echo $OLD_NAME | sed 's/posix/shmozix/g')
    mv "$OLD_NAME" "$NEW_NAME"
done

manntes ★★
()
Ответ на: комментарий от zort

find . -type f | sed -e 's/^(.*)posix(.*)$/mv "\1posix\2" "\1shmozix\2"/' | sh

В sed_овм regexp_e надо backslash_ы расставить, но идея думаю ясна.

sdio ★★★★★
()
Ответ на: комментарий от manntes

>sed 's/ /SpAcE/g'

o_O

спасибо ;)

как я понял других спец-символов он не обработает.

в целях приобритения знаний, ждем "без хаковый" вариант с официальным способом работы с спец-cимволами.

zort
() автор топика
Ответ на: комментарий от zort

Запускай "на посмотреть":
find . -type f | sed -e 's/^\(.*\)posix\(.*\)$/mv "&" "\1shmozix\2"/'

Если все ОК добавь в конце     | sh
find . -type f | sed -e 's/^\(.*\)posix\(.*\)$/mv "&" "\1shmozix\2"/' | sh

sdio ★★★★★
()
Ответ на: комментарий от sdio

>Если все ОК добавь в конце | sh

конечно не сработало - пробелы внутри \1 и \2 просто так в заискейпенные не превратятся.

ЗЫ сорри за промедление - у меня инет отвалился

zort
() автор топика
Ответ на: комментарий от zort

Не понял твоих проблем?

$ ls -1
a1 b1 c1
a2 b2 c2
a3 b3 c3

$ ls -1 | sed 's/^\(.*\)b\(.*\)$/mv "&" "\1bebe\2"/'
mv "a1 b1 c1" "a1 bebe1 c1"
mv "a2 b2 c2" "a2 bebe2 c2"
mv "a3 b3 c3" "a3 bebe3 c3"

$ ls -1 | sed 's/^\(.*\)b\(.*\)$/mv "&" "\1bebe\2"/' | sh

$ ls -1
a1 bebe1 c1
a2 bebe2 c2
a3 bebe3 c3

sdio ★★★★★
()
Ответ на: комментарий от sdio

хмм, да действительно. я просто думал что это окончательный вариант который всё может. у меня были тестовые файлы типа

Akmajian A., et al. Linguistics.. an introduction to language and communication (5ed., MIT, 2001)(L)(T)(309s).djvu

и на скобках не сработало.

спасибо. буду знать что sedом можно в sh плеваться забыв про пробелы.

zort
() автор топика
Ответ на: комментарий от zort

$ ls -1
a1 .,(b1)(d1) c1
a2 .,(b2)(d2) c2
a3 .,(b3)(d3) c3

$ rename -n 's/b/B/' *
a1 .,(b1)(d1) c1 renamed as a1 .,(B1)(d1) c1
a2 .,(b2)(d2) c2 renamed as a2 .,(B2)(d2) c2
a3 .,(b3)(d3) c3 renamed as a3 .,(B3)(d3) c3

sdio ★★★★★
()
Ответ на: комментарий от sdio

rename сработал.

btw rename это perl скрипт, а хочется узнать как это делать башем и стандартными утилитами, ведь не только ренейминг делать приходится, а файлов с паршивыми именами меньше не становится. И в конце концов, возникает вопрос - "а не сакс ли баш вместе с пайпами?" и "не проще ли сразу не перле питоне или джаве писать ?". я всегда говорил что сакс, но сделать можно всё, если знаешь как. и сидя в линуксе я всегда пытаюсь сначала баш скрипт написать. поэтому хочется узнать.

zort
() автор топика
Ответ на: комментарий от zort

>"а не сакс ли баш вместе с пайпами?"
Всему есть свои пределы.
В баше для отработки всех вариантов придется слишком много escape_ов насадить.

>"не проще ли сразу не перле питоне или джаве писать ?"
Нет, по-крайне мере в большинстве случаев.

sdio ★★★★★
()

Я бы сделал так:

[tmp]> ls -1
aa
aa posixbb q
'posixq w
z's" posix'" q
[tmp]> oldIFS="$IFS"
[tmp]> IFS='      <-- здесь я нажал Enter сразу после кавычки
> '               <-- а здесь ввёл кавычку и нажал Enter; > - это $PS2
[tmp]> for f in `find -type f`; do mv -v "$f" "`sed 's,posix,shmozix,' <<< "$f"`"; done
`./aa posixbb q' -> `./aa shmozixbb q'
mv: `./aa' и `./aa' - один и тот же файл
`./\'posixq w' -> `./\'shmozixq w'
`./z\'s" posix\'" q' -> `./z\'s" shmozix\'" q'
[tmp]> ls -1
aa
aa shmozixbb q
'shmozixq w
z's" shmozix'" q
[tmp]> IFS="$oldIFS"
[tmp]> unset oldIFS

Jini ★★
()
Ответ на: комментарий от Jini

а как нибудь в вид скрипта, чтобы для теста в исп. файл заталкать легко было, это можно превратить?

zort
() автор топика
Ответ на: комментарий от sdio

>Всему есть свои пределы.

понятно, т.е. работать с именем файла как с чем-то неделимым а баше нельзя.

zort
() автор топика
Ответ на: комментарий от zort

Пожалуйста:

#!/bin/bash

IFS='
'
for f in `find "$3" -type f`; do
 mv -v "$f" "`sed "s,$1,$2," <<< "$f"`"
done

Первый параметр - что заменить, второй - на что заменить, третий - где заменить.

Jini ★★
()
Ответ на: комментарий от zort

И что у тебя не получилось в баше с со скобками или с др. символами?

Пока все работает. Дай пример файла, на котором мой "find | sed | sh" валится.

sdio ★★★★★
()
Ответ на: комментарий от Jini

Что-то больно похоже на первый скрипт. Не загнётся ли оно ещё на for f in ...

manntes ★★
()
Ответ на: комментарий от sdio

Стандартные утилиты, баш, скобки и пробелы обрабатываются корректно:

#!/bin/bash
for FILE_NAME in $(find . -type f | sed 's/ /%20/g; s/(/%28/g; s/)/%29/g')
do
    OLD_NAME=$(echo $FILE_NAME | sed 's/%20/ /g; s/%28/(/g; s/%29/)/g')
    NEW_NAME=$(echo $OLD_NAME | sed 's/language/язык/g')
    mv "$OLD_NAME" "$NEW_NAME"
done

Что ещё?

manntes ★★
()
Ответ на: комментарий от manntes

работает, по крайней мере на тех файлах которые у меня, но метод какой то не программистский.

zort
() автор топика
Ответ на: комментарий от sdio

> Пока все работает. Дай пример файла, на котором мой "find | sed | sh" валится.

[tmp2]> ls -1
a"bebeqq
[tmp2]> ls -1 | sed 's/^\(.*\)bebe\(.*\)$/mv -v "&" "\1ihuh\2"/' | sh
mv: после `abebeqq aihuhqq' пропущен операнд, задающий целевой файл
Попробуйте `mv --help' для получения более подробного описания.
[tmp2]> ls -1 | sed 's/^\(.*\)bebe\(.*\)$/mv -v "&" "\1ihuh\2"/'     
mv -v "a"bebeqq" "a"ihuhqq"
[tmp2]> cat ../rename.sh 
#!/bin/bash

IFS='
'
for f in `find "$3" -type f`; do
 mv -v "$f" "`sed "s,$1,$2," <<< "$f"`"
done
[tmp2]> ../rename.sh bebe ihuh .
`./a"bebeqq' -> `./a"ihuhqq'
[tmp2]> ls
a"ihuhqq

Jini ★★
()
Ответ на: комментарий от zort

Главное - что бы работало :) Линукс то же был не идеалом, но работал, пока Хурд стремился и стремился к идеалу :)

manntes ★★
()
Ответ на: комментарий от Jini

не разбирался из-за чего, но у меня на таких файлах как "CCCCCC,CCCCCCBB Sethi, !"&#8470;;"&#8470;;"&#8470;:&#8470;:%?*()(*?Ёёё`` ```$Ul``lman. Compilers.. principles, techniques, and tools (AW, 1986)(100dpi)(T)(811s)_S_" не сработало. я ужесточил задание. у mantes сработало.

zort
() автор топика
Ответ на: комментарий от sdio

> Следующий!

Твой скрипт валится на любых спецсимволах - ', (, { - ты так и будешь добавлять их в код?

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

Jini ★★
()
Ответ на: комментарий от Jini

Правильный вариант -- не писать на баше (если только это не сделанно специально), там где есть более одной интерпритации/подстановки строки (из-за возможных спецсимволов).
И это не потому что баш плохой, это особенности вложенных интерпритаций/подстановки.
На perl, в программе rename например, переменные не раскрываются более одного раза (если только это не сделанно специально).

sdio ★★★★★
()
Ответ на: комментарий от zort

[tmp2]> ls 
a`ihuhqq
[tmp2]> ../rename.sh ihuh uhih .
`./a`ihuhqq' -> `./a`uhihqq'
[tmp2]> ls
a`uhihqq

У меня сработало. И с той большой строкой тоже. Хотя там форум часть символов попортил...

Jini ★★
()
Ответ на: комментарий от Jini

>Твой скрипт валится на любых спецсимволах - ', (, { 

Можете продемонстрировать?

sed 's/["`$]/\\&/g; s/^\(.*\)a\(.*\)$/mv "&" "\1mymy\2"/;'

sdio ★★★★★
()
Ответ на: комментарий от Jini

не знаю, может быть я что то испортил. посмотри.

zort@lambda:~/asd/rewq$ ls
BBBBB  BBBBBB`BBBB

zort@lambda:~/asd/rewq$ cat ../fdsa
#!/bin/bash

asdfasdf="BBBB"
fdsafdsa="DDDD"

IFS='
'
for f in `find "$3" -type f`; do
 mv -v "$f" "`sed "s,$asdfasdf,$fdsafdsa," <<< "$f"`"
done

zort@lambda:~/asd/rewq$ cat ../asdf
#!/bin/bash
for FILE_NAME in $(find . -type f | sed 's/ /%20/g; s/(/%28/g; s/)/%29/g')
do
    OLD_NAME=$(echo $FILE_NAME | sed 's/%20/ /g; s/%28/(/g; s/%29/)/g')
    NEW_NAME=$(echo $OLD_NAME | sed 's/BBBBB/CCCCCC/g')
    mv "$OLD_NAME" "$NEW_NAME"
done

zort@lambda:~/asd/rewq$ ./../fdsa
find: invalid predicate `'

zort@lambda:~/asd/rewq$ ls -1
BBBBB
BBBBBB`BBBB
zort@lambda:~/asd/rewq$ ./../asdf

zort@lambda:~/asd/rewq$ ls -1
CCCCCC
CCCCCCB`BBBB

zort
() автор топика
Ответ на: комментарий от sdio

сделай то что заменять BBB, то чем ССС, а то у меня мозг от этих слешей вскипает.

zort
() автор топика
Ответ на: комментарий от sdio

> Правильный вариант -- не писать на баше (если только это не сделанно специально), там где есть более одной интерпритации/подстановки строки (из-за возможных спецсимволов).

Вот я ещё буду на каждый чих перл привлекать :) Мне как-то хватало башевской защиты от спецсимволов.

> На perl, в программе rename например, переменные не раскрываются более одного раза (если только это не сделанно специально).

Если так важна скорость, то, может быть, баш и не лучший вариант. Но для повседневных задач это вполне достаточный инструмент для работы с файловой системой.

Jini ★★
()
Ответ на: комментарий от zort

> не знаю, может быть я что то испортил. посмотри.

У тебя получилось так, что в моём скрипте $3 не определён. В моих примерах там стояла точка, что значит "текущая директория". Замени $3 на . или на путь, где лежат файлы, которые надо переименовать.

Jini ★★
()
Ответ на: комментарий от Jini

у меня стабильно на ` ругается.

скрипт:

#!/bin/bash

IFS='
'
for f in `find "$3" -type f`; do
 mv -v "$f" "`sed "s,$1,$2," <<< "$f"`"
done

версии софта:

GNU bash, version 3.1.17(1)-release (i486-pc-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
zort@lambda:~/asd/rewq$ find --version
GNU find version 4.2.28
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION
zort@lambda:~/asd/rewq$ sed --version
GNU sed version 4.1.5
Copyright (C) 2003 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,
to the extent permitted by law.

zort
() автор топика

теперь конкурс на tar файл внутри которого будут файлы которые не будут переименованы скриптом manntes. или док-во что таких существовать не может.

zort
() автор топика
Ответ на: комментарий от Jini

ну я и стормозил, я в упор не видел этот $3

зачот !

zort
() автор топика
Ответ на: комментарий от Jini

>Вот я ещё буду на каждый чих перл привлекать :) 

ls -1 | perl -ne 'chomp; $from="$_"; rename "$from", "$_" if (s/BBB/CCC/);'

Сильно сложно?

sdio ★★★★★
()
Ответ на: комментарий от zort

> т.е. твой скрипт универсален ? для всеx допустимых в линуксе имен файлов ?

Не уверен. Скорее всего, да.

Jini ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.