Рекурсивно переименовывать файлы, используя find и sed - PullRequest
76 голосов
/ 25 января 2011

Я хочу просмотреть несколько каталогов и переименовать все файлы, заканчивающиеся на _test.rb, заканчивающиеся на _spec.rb.Это то, чего я никогда не понимал, как поступить с bash, поэтому на этот раз я подумал, что приложу некоторые усилия, чтобы добиться этого.Хотя я пока что не понял, мои лучшие усилия:

find spec -name "*_test.rb" -exec echo mv {} `echo {} | sed s/test/spec/` \;

Примечание: после exec есть дополнительное эхо, так что команда печатается вместо запуска, пока я ее тестирую.

Когда я запускаю его, для каждого совпавшего имени файла выводится:

mv original original

, то есть замена на sed была потеряна.В чем прикол?

Ответы [ 19 ]

1 голос
/ 25 января 2011

если у вас есть Ruby (1.9 +)

ruby -e 'Dir["**/*._test.rb"].each{|x|test(?f,x) and File.rename(x,x.gsub(/_test/,"_spec") ) }'
1 голос
/ 04 декабря 2014

Я смог обработать имена файлов с пробелами, следуя примерам , предложенным onitake.

Это не прерывается, если путь содержит пробелы или строку test:

find . -name "*_test.rb" -print0 | while read -d $'\0' file
do
    echo mv "$file" "$(echo $file | sed s/test/spec/)"
done
1 голос
/ 31 июля 2012

В ответе ramtam, который мне нравится, часть find работает нормально, а остальная часть - нет, если путь содержит пробелы.Я не слишком знаком с sed, но мне удалось изменить этот ответ следующим образом:

find . -name "*_test.rb" | perl -pe 's/^((.*_)test.rb)$/"\1" "\2spec.rb"/' | xargs -n2 mv

Мне действительно нужно было такое изменение, потому что в моем случае команда final выглядит больше как

find . -name "olddir" | perl -pe 's/^((.*)olddir)$/"\1" "\2new directory"/' | xargs -n2 mv
1 голос
/ 28 сентября 2015

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

find spec -name "*_test.rb" -print0 | while read -d $'\0' file; do mv "$file" "`echo $file | sed s/test/spec/`"; done
0 голосов
/ 01 июня 2019

Я делюсь этим постом, так как он немного связан с вопросом. Извините за не предоставление более подробной информации. Надеюсь, это поможет кому-то еще. http://www.peteryu.ca/tutorials/shellscripting/batch_rename

0 голосов
/ 25 января 2011
$ find spec -name "*_test.rb"
spec/dir2/a_test.rb
spec/dir1/a_test.rb

$ find spec -name "*_test.rb" | xargs -n 1 /usr/bin/perl -e '($new=$ARGV[0]) =~ s/test/spec/; system(qq(mv),qq(-v), $ARGV[0], $new);'
`spec/dir2/a_test.rb' -> `spec/dir2/a_spec.rb'
`spec/dir1/a_test.rb' -> `spec/dir1/a_spec.rb'

$ find spec -name "*_spec.rb"
spec/dir2/b_spec.rb
spec/dir2/a_spec.rb
spec/dir1/a_spec.rb
spec/dir1/c_spec.rb
0 голосов
/ 25 января 2011

Ваш вопрос, похоже, о sed, но для достижения вашей цели рекурсивного переименования я бы предложил следующее, бесстыдно оторванное от другого ответа, который я дал здесь: рекурсивное переименование в bash

#!/bin/bash
IFS=$'\n'
function RecurseDirs
{
for f in "$@"
do
  newf=echo "${f}" | sed -e 's/^(.*_)test.rb$/\1spec.rb/g'
    echo "${f}" "${newf}"
    mv "${f}" "${newf}"
    f="${newf}"
  if [[ -d "${f}" ]]; then
    cd "${f}"
    RecurseDirs $(ls -1 ".")
  fi
done
cd ..
}
RecurseDirs .
0 голосов
/ 23 октября 2014

Более безопасный способ переименования с помощью find utils и типа регулярного выражения sed:

  mkdir ~/practice

  cd ~/practice

  touch classic.txt.txt

  touch folk.txt.txt

Удалите расширение .txt.txt следующим образом -

  cd ~/practice

  find . -name "*txt" -execdir sh -c 'mv "$0" `echo "$0" | sed -r 's/\.[[:alnum:]]+\.[[:alnum:]]+$//'`' {} \;

Если вы используете + вместо; чтобы работать в пакетном режиме, указанная выше команда переименует только первый соответствующий файл, но не весь список совпадений файлов с помощью команды «find»

  find . -name "*txt" -execdir sh -c 'mv "$0" `echo "$0" | sed -r 's/\.[[:alnum:]]+\.[[:alnum:]]+$//'`' {} +
0 голосов
/ 15 апреля 2015

Вот хороший приятель, который добивается цели.Sed не может обработать это правильно, особенно если множественные переменные передаются xargs с -n 2. Подстановка bash легко это обработает, например:

find ./spec -type f -name "*_test.rb" -print0 | xargs -0 -I {} sh -c 'export file={}; mv $file ${file/_test.rb/_spec.rb}'

Добавление -type -f ограничит операции перемещения дотолько файлы, -print 0 будет обрабатывать пустые места в путях.

...