Массовое переименование файлов из текстового файла

Когда оболочка выполняет внешнюю команду, длина командной строки после расширения любого шаблона подстановки имени файла, такого как *, не должна превышать определенной длины.

В вашем случае grep 'PATTERN' *превращается в слишком длинную команду для выполнения оболочкой.

Во втором примере:

for i in $(`cat MyFiles`); do echo $i; done

вы пытаетесь перебрать имена файлов, хранящиеся в MyFiles, но вы очень неправильно понимаете синтаксис.

$(`cat MyFiles`)

совпадает с

$( $(cat MyFiles) )

, что означает, что содержимое MyFilesбудет интерпретироваться как команда. Вот почему вы получаете ошибку command not found.

Есть несколько способов исправить это.но перебирать содержимое вашего файла в цикле не очень хорошо.

Стивен дает хорошее решение в своем ответе , а другое решение, предполагая, что ваш текущий рабочий каталог — это папка Maildir,

find. -type f -exec grep 'PATTERN' {} +

Это выполнит grepнесколько раз для как можно больших пакетов файлов .

Это похоже на

printf '%s\n' * | xargs grep 'PATTERN'

, но команда findобрабатывает имена файлов с пробелами и встроенными символами новой строки.

Команда printfвыводит одно имя файла в строке. У него нет той же проблемы, что и у grep 'PATTERN' *, так как это, скорее всего, , встроенная -в команду , и поэтому ее не нужно выполнять в оболочке как внешнюю команду.

Ваше циклическое решение также будет работать, но вместо того, чтобы перебирать результат cat, вы можете просто выполнить

for name in *; do
    grep 'PATTERN' "$name"
done

Это предполагает, что в текущем каталоге есть только обычные файлы .

Чтобы убедиться, что вы обрабатываете только почтовые сообщения, вы можете использовать

for name in *,*; do
    grep 'PATTERN' "$name" /dev/null
done

Перебирает имена, которые содержат хотя бы одну запятую. Я также добавил /dev/null, чтобы заставить grepвыводить имена файлов, соответствующие заданному шаблону. Вы можете удалить /dev/nullи вместо этого использовать -Hс grep, если ваш grepподдерживает это.

Подобный цикл выполняется медленно, поскольку мы выполняем grepодин раз для каждого отдельного файла в каталоге.

0
25.11.2019, 20:59
3 ответа

На вашем месте я бы сделал это небольшими партиями и проверил с копией, но что-то вроде этого подойдет вам

while read n; do read f; mv $f "$n.${f##*.}"; done < file

Прежде чем начать, рекомендуется проверить вывод

while read n; do read f; echo mv $f "$n.${f##*.}"; done < file > checkfile

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

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

while read n; do read f; cp $f "/a/safe/location/$n.${f##*.}"; done < file

Примечание

Чтобы отменить процесс, вам просто нужно изменить порядок имен в команде mv

mv "$n.${f##*.}"  $f
0
28.01.2020, 02:29

Предполагая, что "it's name example" — это строка в строке непосредственно над текущим .mkvименем файла, т. е. заданным

$ cat file.txt 
Taken S01 E01
74857.mkv
Taken S01 E02
74858.mkv

ты действительно хочешь

74857.mkv > Taken S01 E01.mkv

74858.mkv > Taken S01 E02.mkv

, затем с GNU parallelиmv:

parallel -N2 echo mv -- {2} {1}.mkv < file.txt

Удалите echo, как только убедитесь, что он составляет правильные команды.

2
28.01.2020, 02:29

Сperl:

perl -lne '$dst = "$_.mkv"; $src = <>; chomp $src; rename $src, $dst
  or warn "$src -> $dst: $!\n"' your-file

Сzsh:

zmodload zsh/files # to get a builtin mv
while IFS= read -ru3 dst && IFS= read -ru3 src; do
   mv -- "$src" "$dst.mkv"
done 3< your-file
0
28.01.2020, 02:29

Теги

Похожие вопросы