Используйте bash для замены подстроки в имени файла новой подстрокой, основанной на попарных (старых, новых) значениях в файле .csv - PullRequest
0 голосов
/ 07 февраля 2020

У меня есть каталог, содержащий сотни файлов изображений, каждый из которых назван по-разному, например:

abdogf.png

abcatf.png

abhorsef.png

Я создал файл changenames.csv, содержащий два столбца со старыми строками в первом столбце и новыми строками во втором, например:

"собака", "woof"

"кошка" , "miaow"

"horse", "lie"

Эти строки в настоящее время в кавычках, как показано.

Я хотел бы вызвать команду bash или сценарий. sh из командной строки для замены каждой подстроки oldstring каждой подстрокой newstring в именах файлов каталога (не в содержимом файла), так что каталог недавно содержит файлы с именем:

abwooff.png

abmiaowf.png

abneighf.png

вместо исходных файлов.

Я пробовал различные решения, такие как https://superuser.com/questions/508731/find-and-replace-string-in-filenames/508758#508758 и Как найти и заменить часть имен файлов из списка безуспешно.

Например, я попытался вызвать в каталоге следующее с файлами:

#!/bin/bash
inputfile=${1}
while read line
do
    IFS=',' read -a names <<< "${line}"
    for file in `find . -maxdepth 1 -type f -name "*${names[0]}*"`; do
        rename "s/${names[0]}/${names[1]}/" *
    done
done < ${inputfile}

с помощью командной строки test test. sh changenames.csv.

Это не приводит к ошибке, но не вносит изменений в имена файлов.

Я также пробовал это решение { ссылка }, которое привело к ошибке, в которой @echo не был распознанная команда.

Заранее благодарю за любую помощь.

Ответы [ 2 ]

1 голос
/ 07 февраля 2020

Сначала нужно удалить двойные кавычки. Код пытается найти файлы, такие как *"cat"*, которые не выходят.
Более того, вам не нужно выполнять команду find. Вы вообще не используете переменную file.
Не могли бы вы попробовать следующее:

while IFS=',' read -r old new; do
    old=${old//\"/}     # remove leading and trailing double-quotes
    new=${new//\"/}     # same as above
    rename "s/$old/$new/" *
done < "$1"
0 голосов
/ 07 февраля 2020

IFS=',' read -a names <<< "${line}" не удаляет " со входа. В ваших именах файлов нет ", поэтому вы также должны их удалить.

Backticks `не рекомендуется. Не используйте их. Вместо этого используйте $(....).

"для файла в` "так же плохо, как и for file in $(cat) - это обычный bash антипаттерн. Не используйте его - у вас будут проблемы с элементами с пробелами или табуляцией. Используйте while IFS= read -r line, чтобы прочитать что-то вроде строки.

Проблема с rename, есть две распространенные версии rename - GNU rename и perl переименовать . Похоже, ваш сценарий нацелен на версию perl - убедитесь, что она установлена.

Пусть rename сделает переименование - здесь for file in find не требуется.

Если Вы делаете while read line, а затем IFS=, read <<<"$line" дублирует работу, просто сделайте while IFS=, read -a names; do с самого начала.

Так что вы можете сделать:

# split the input on ','
while IFS=',' read -r pre post; do
    # remove quotes
    pre=${pre//\"/}
    post=${post//\"/}
    # do the rename
    rename "s/${pre}/${post}/" *
done < ${inputfile}

Я думаю, я бы сделал следующий скрипт, который использует sed:

# find all files in a directory
find . -maxdepth 1 -type f |
# convert filenames into pairs (filename,new_filename) separated by newline
sed "
   # hold the line in hold space
   h
   # replace the characters as in the other file
   $(
      # generate from "abc","def" -> s"abc"def"g
      sed 's@"\([^"]*\)","\([^"]*\)"@s"\1"\2"g@' changenames.csv
   )
   # switch pattern and hold space
   x
   # append the line
   G
   # remove the line if substitute is the same
   /^\(.*\)\n\1$/d
" |
# outputs two lines per each filename:
# one line with old filename and one line with new filename
# so just pass that to mv
xargs -l2 echo mv -v

и один вкладыш:

 find . -maxdepth 1 -type f | sed "h;$(sed 's@"\([^"]*\)","\([^"]*\)"@s"\1"\2"g@' changenames.csv);x;G; /^\(.*\)\n\1$/d" | xargs -l2 echo mv -v

со следующей структурой воссоздания файлов:

touch  abdogf.png abcatf.png abhorsef.png
cat <<EOF >changenames.csv
"dog","woof"
"cat","miaow"
"horse","neigh"
EOF

скрипт выходы на репле :

mv -v ./abdogf.png ./abwooff.png
mv -v ./abcatf.png ./abmiaowf.png
mv -v ./abhorsef.png ./abneighf.png
...