Производительность с помощью цикла bash при переименовании файлов - PullRequest
2 голосов
/ 25 декабря 2011

Иногда мне нужно переименовать некоторое количество файлов, например добавить префикс или удалить что-то.Сначала я написал скрипт на Python.Это хорошо работает, и я хочу версию оболочки.Поэтому я написал что-то вроде этого:

$ 1 - какой каталог перечислить, $ 2 - какой шаблон будет заменой, $ 3 - заменой.

echo "usage: dir pattern replacement"
for fname in `ls $1`
do
  newName=$(echo $fname | sed "s/^$2/$3/")
  echo 'mv' "$1/$fname" "$1/$newName&&"
  mv "$1/$fname" "$1/$newName"
done

Это работает, но очень медленно, возможно потому, что этонеобходимо создать процесс (здесь sed и mv), уничтожить его и создать тот же процесс снова, чтобы иметь другой аргумент.Это правда?Если да, то как этого избежать, как получить более быструю версию?

Я подумал предложить всем обработанным файлам имя (используя sed для их одновременной обработки), но ему все еще нужно mv в цикле.

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

--- update ---

Прошу прощения за описание.Мой основной вопрос: «Если мы должны использовать какую-то команду в цикле, это снизит производительность?»Потому что в for i in {1..100000}; do ls 1>/dev/null; done создание и уничтожение процесса займет большую часть времени.Так что я хочу: «Есть ли способ уменьшить эту стоимость?».

Спасибо kev и SRI за предоставление мне rename решения для переименования файлов.

Ответы [ 4 ]

2 голосов
/ 25 декабря 2011

Каждый раз, когда вы вызываете внешний двоичный файл (ls, sed, mv), bash вынужден сам форкаться, чтобы выполнить команду, и это сильно сказывается на производительности.

Вы можете делать все, что хотите, в чистом bash 4.X, и вам нужно только позвонить mv

pat_rename(){ 
  if [[ ! -d "$1" ]]; then
    echo "Error: '$1' is not a valid directory"
    return
  fi
  shopt -s globstar
  cd "$1"
  for file in **; do
    echo "mv $file ${file//$2/$3}"
  done
}
1 голос
/ 25 декабря 2011

Сначала самое простое.Что не так с rename?

mkdir tstbin
for i in `seq 1 20`
do
   touch tstbin/filename$i.txt
done
rename .txt .html tstbin/*.txt

Или вы используете старую * nix машину?

0 голосов
/ 26 декабря 2011

Я думаю, что вы можете сохранить все имена файлов в файл или строку, и использовать awk и sed сделать это один раз вместо одного за другим.

0 голосов
/ 25 декабря 2011

Чтобы избежать повторного выполнения sed для каждого файла, вместо этого вы можете настроить два потока имен, один исходный и один преобразованный, а затем выполнить sip с концов:

exec 3< <(ls)
exec 4< <(ls | sed 's/from/to/')

IFS=`echo`
while read -u3 orig && read -u4 to; do
    mv "${orig}" "${to}";
done;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...