Использование sed для массового переименования файлов - PullRequest
72 голосов
/ 03 марта 2010

Цель

Изменить эти имена файлов:

  • F00001-0708-RG-biasliuyda
  • F00001-0708-CS-akgdlaul
  • F00001-0708-VF-hioulgigl

к этим именам файлов:

  • F0001-0708-RG-biasliuyda
  • F0001-0708-CS-akgdlaul
  • F0001-0708-VF-hioulgigl

Код оболочки

Для проверки:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/'

Для выполнения:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' | sh

Мой вопрос

Я не понимаю код sed. Я понимаю какая замена Команда

$ sed 's/something/mv'

означает. И я немного понимаю регулярные выражения. Но я не понять, что здесь происходит:

\(.\).\(.*\)

или здесь:

& \1\2/

Первое, для меня, просто выглядит так, как будто это означает: «один персонаж, сопровождаемый единственным символом, сопровождаемым любой последовательностью длины один символ "- но, безусловно, есть нечто большее, чем это. Насколько последняя часть:

& \1\2/

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

Ответы [ 10 ]

129 голосов
/ 03 марта 2010

Во-первых, я должен сказать, что самый простой способ сделать это - использовать команды prename или rename.

В Ubuntu, OSX (пакет Homebrew rename, пакет MacPorts p5-file-rename) или других системах с переименованием perl (prename):

rename s/0000/000/ F0000*

или в системах с переименованием из util-linux-ng, таких как RHEL:

rename 0000 000 F0000*

Это гораздо более понятно, чем эквивалентная команда sed.

Но для понимания команды sed полезна man-страница sed. Если вы запускаете man sed и ищете & (используя команду / для поиска), вы найдете его в s / foo / bar / replacements.

  s/regexp/replacement/
         Attempt  to match regexp against the pattern space.  If success‐
         ful,  replace  that  portion  matched  with  replacement.    The
         replacement may contain the special character & to refer to that
         portion of the pattern space  which  matched,  and  the  special
         escapes  \1  through  \9  to refer to the corresponding matching
         sub-expressions in the regexp.

Следовательно, \(.\) соответствует первому символу, на который может ссылаться \1. Тогда . соответствует следующему символу, который всегда равен 0. Тогда \(.*\) соответствует остальной части имени файла, на которое может ссылаться \2.

Строка замены складывает все вместе, используя & (оригинал имя файла) и \1\2, которая является каждой частью имени файла, кроме 2-го символ, который был 0.

Это довольно загадочный способ сделать это, ИМХО. Если для по какой-то причине команда переименования была недоступна, и вы хотели использовать sed, чтобы сделать переименование (или, возможно, вы делали что-то слишком сложное для переименования?), более явное в вашем регулярном выражении сделало бы это много более читабельным. Возможно что-то вроде:

ls F00001-0708-*|sed 's/F0000\(.*\)/mv & F000\1/' | sh

Возможность увидеть, что на самом деле меняется в s / search / replace / делает его намного более читабельным. Также это не будет держать высасывая символы из вашего имени файла, если вы случайно запустили его дважды или что-то.

37 голосов
/ 03 марта 2010

у вас есть объяснение sed, теперь вы можете использовать только оболочку, не нужно внешних команд

for file in F0000*
do
    echo mv "$file" "${file/#F0000/F000}"
    # ${file/#F0000/F000} means replace the pattern that starts at beginning of string
done
16 голосов
/ 22 июня 2013

Я написал небольшой пост с примерами пакетного переименования, используя sed пару лет назад:

http://www.guyrutenberg.com/2009/01/12/batch-renaming-using-sed/

Например:

for i in *; do
  mv "$i" "`echo $i | sed "s/regex/replace_text/"`";
done

Еслирегулярное выражение содержит группы (например, \(subregex\), тогда вы можете использовать их в тексте замены как \1\, \2 и т. д.

14 голосов
/ 01 сентября 2013

Самый простой способ будет:

for i in F00001*; do mv "$i" "${i/F00001/F0001}"; done

или, переносимо,

for i in F00001*; do mv "$i" "F0001${i#F00001}"; done

Заменяет префикс F00001 в именах файлов на F0001. кредиты Махешу здесь: http://www.debian -administration.org / Articles / 150

6 голосов
/ 03 марта 2010

Команда sed

s/\(.\).\(.*\)/mv & \1\2/

означает заменить:

\(.\).\(.*\)

с:

mv & \1\2

как обычная команда sed. Однако круглые скобки, маркеры & и \n немного меняют его.

Строка поиска соответствует (и запоминает как образец 1) один символ в начале, за которым следует один символ, за которым следует остальная часть строки (запоминается как образец 2).

В строке замены вы можете ссылаться на эти совпавшие шаблоны, чтобы использовать их как часть замены. Вы также можете ссылаться на всю подобранную часть как &.

Итак, команда sed создает команду mv на основе исходного файла (для источника) и символов 1 и 3 и далее, эффективно удаляя символ 2 (для места назначения). Это даст вам ряд строк в следующем формате:

mv F00001-0708-RG-biasliuyda F0001-0708-RG-biasliuyda
mv abcdef acdef

и т. Д.

2 голосов
/ 03 марта 2010

Материал с обратной косой чертой означает, что «при сопоставлении с шаблоном, держитесь за материал, который здесь соответствует». Позже, на стороне замены текста, вы можете вернуть эти запомненные фрагменты с помощью «\ 1» (первый блок в скобках), «\ 2» (второй блок) и т. Д.

0 голосов
/ 28 августа 2013

Вот что я бы сделал:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done

Тогда, если все выглядит хорошо, добавьте | sh в конец. Итак:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done | sh
0 голосов
/ 04 марта 2010
 ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash
0 голосов
/ 03 марта 2010

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

s/.//2

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

Это не более читабельно, чем ваша версия:

find -type f | sed -n 'h;s/.//4;x;s/^/mv /;G;s/\n/ /g;p' | sh

Четвертый символ удален, потому что find добавляет каждое имя файла к имени "./".

0 голосов
/ 03 марта 2010

В скобках указаны определенные строки для использования с обратными слешами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...