2010-03-03 2 views
56

ЦельИспользование СЭД массировать переименовывать файлы

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

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

к этим именам:

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

Shell Код

Для теста:

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

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

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

Мой вопрос

Я не понимаю СЕПГ код. Я понимаю, что замена команда

$ sed 's/something/mv' 

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

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

или здесь:

& \1\2/ 

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

& \1\2/ 

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

+0

См. Также: [Изменение расширений файлов с помощью sed] (https: // stackoverflow.com/questions/44620236/change-file-extensions-with-sed/44620449 # 44620449) – agc

ответ

115

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

В Ubuntu, OSX (Доморощенный пакет rename, MacPorts пакет p5-file-rename), или другие системы с Perl переименованью (prename):

rename s/0000/000/ F0000* 

или на системы с переименованью из Util-Linux-нг, такие как RHEL :

rename 0000 000 F0000* 

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

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

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.

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

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

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

+1

на моем сервере RHEL, синтаксис переименования будет «переименовать 0000 000 F0000 *» –

+0

В моей установке ArchLinux 's ///' должен быть '-s ///', иначе он жалуется на «слишком много аргументов». –

+1

Скорее всего, 'rename' сам переименовывается * *. т.е. 'rename' был *« переименован »* из' prename' .. например, в Ubuntu: 'readlink -f $ (который переименовывает)' выдает '/ usr/bin/prename' ...' rename', упомянутый * Дэвид * совсем другая программа. –

2

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

0

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

35

вы имели свой 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 
+0

Приятно, но вы не можете ссылаться на круглые скобки , –

4

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 

и так далее.

+1

Это было хорошее объяснение, но было бы полезно указать, как вы используете команду sed с другими командами для фактического переименования файлов. Например: 'ls | sed "s /\(.\).\(.*\)/ mv & \ 1 \ 2 /" | bash' – jcarballo

+0

@jcarballo: опасно разбирать 'ls', pipe через' sed' и _then pipe через оболочку! _ он подвержен произвольному исполнению кода с поддельными именами файлов. Проблема в том, что данные следует рассматривать как данные, и здесь он обычно сериализуется в код без каких-либо предосторожностей. Я хочу, чтобы paxdiablo мог удалить этот ответ, поскольку он действительно не показывает хорошую практику. (Я наткнулся на этот вопрос, потому что новичок случайно отправил '' sh' после команды, которая не сработала, и, увидев этот вопрос, и ответы подумали, что это будет работать лучше - я в ужасе!) ':)'. –

0

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

s/.//2 

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

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

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

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

+0

Я хочу, чтобы вы могли удалить этот ответ. Хотя, возможно, это хорошо в самом конкретном случае OP, есть много людей, которые видят такие ответы, и не понимают этого, и беспорядочно трубу '| sh' после команды, которая не работает, в надежде, что она будет работать лучше. Это ужасно! (и, кроме того, это не хорошая практика). Надеюсь, вы поймете! –

0
ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash 
+0

Ужасно! при условии выполнения произвольного кода (возможно, не в конкретном контексте вопроса, но есть много людей, которые видят ответы, подобные этому, и пытаются случайным образом напечатать что-то похожее на него, и это пугает опасно!). Я бы хотел, чтобы вы удалили этот ответ (кроме того, у вас есть еще один хороший, который я поддержал). –

12

Я написал небольшой пост с примерами на пакетном переименовании используя 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 и т. Д.

+0

Обратите внимание, что ссылки только для ответов не приветствуются (ссылки имеют тенденцию устаревать с течением времени). Пожалуйста, рассмотрите возможность редактирования своего ответа и добавления краткого описания здесь. – kleopatra

0

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

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 
14

Проще всего было бы:

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

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

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

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

+2

Вы должны правильно указать переменные-интерполяции; 'mv" $ i "" $ {i/F00001/F0001} "'. Но +1 – tripleee

Смежные вопросы