2016-09-05 3 views
1

У меня есть несколько каталогов, содержащих файлы, имена которых содержат имя папки, другие слова. Пример:Linux Bash - Как удалить часть имени файла, содержащегося в папке

one/berg - one.txt 
two/tree - two.txt 
three/water - three.txt 

, и я хотел бы остаться так:

one/berg.txt 
two/tree.txt 
three/water.txt 

Я попытался с SED команды, найти команду, для команды и т.д. я не должен найти способ, чтобы получить Это.

Не могли бы вы мне помочь ?. Спасибо

+1

Действительно ли путь к файлу 'one/berg - one.txt', или это' one/berg - one.txt'? – redneb

+0

[изменить] ваш вопрос и используйте кнопку '{}', чтобы сделать ваш пример разборчивым. –

+0

Sí ./uno/filename - uno.txt - И я хочу удалить имя каталога в имени файла. –

ответ

1

Короткие и простой, если у вас есть GNU найти:

find . -name '* - *.*' -execdir bash -c ' 
    for file; do 
    ext=${file##*.} 
    mv -- "$file" "${file%% - *}.${ext}" 
    done 
' _ {} + 

  • -execdir выполняет заданную команду в каталоге, где находится каждый набор файлов, так что один не нужно беспокоиться о именах каталогов.
  • for file; do - это более короткий способ написать for file in "[email protected]"; do.
  • ${file##*.} расшифровывается до содержания $file, удаляется все, вплоть до последнего . (таким образом, оно расширяется до расширения файла).
  • "${varname%% - *}" расширяет содержимое переменной varname, со всем после <space><dash><space> удаляется с конца.
  • В идиомы -exec bash -c '...' _ {} + (как и с -execdir), сценарий передается bash -c запускается с _ как $0, и все файлы найдены find в последующих положениях.
+0

Работает правильно. спасибо –

0

Вот способ сделать это с помощью СЭД:

#!/bin/bash 

find -type f -print0 | \ 
    while IFS= read -r -d '' old_path; do 
     new_path="$(echo "$old_path" | sed -e 's|/\([^/]\+\)/\([^/]\+\) - \1.\([^/.]\+\)$|/\1/\2.\3|')" 
     if [[ $new_path != $old_path ]]; then 
      echo mv -- "$old_path" "$new_path" 
      # ^^^^ remove this "echo" to actually rename the files 
     fi 
    done 

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

Основная идея состоит в том, что мы перебираем все файлы и для каждого файла, мы пытаемся найти, соответствует ли файл заданному шаблону. Если это произойдет, мы переименуем его. Шаблон обнаруживает (и захватывает) второй последний компонент пути, а также разбивает последний компонент пути на 3 части: префикс, суффикс (который должен совпадать с предыдущим компонентом пути) и расширение.

+0

. Мое самое большое беспокойство об этом подходе, кстати, заключается в том, что он плохо ведет себя с именами файлов, содержащими литералы новой строки, которые обычные файловые системы UNIX разрешают на практике, хотя POSIX этого не требует. Если вы собираетесь использовать «поиск», лучше использовать '-print0' и, соответственно,' IFS = read -r -d '' old_path'. –

+0

El funcionamiento del script es correcto. Eso эпохи lo que buscaba. Muchas gracias. –

+0

(«самый большой» - другой вызывает «sed» в цикле, что является видом практики, которая дает оболочке большую, чем заслуженную репутацию, за то, что она медленная, мы используем fork + exec накладные расходы для вызова 'mv 'независимо от того, что это значит, но это означает дополнительную вилку, чтобы создать подселочку, запускающую' sed', еще один 'exec', FIFO, который будет настроен, а затем прочитан, чтобы прочитать вывод подпроцесса и т. д.). –

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