Как рекурсивно найти и заменить целые файлы на bash? - PullRequest
0 голосов
/ 11 февраля 2020

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

/2019/01/
file1.pdf
file2.pdf

/2019/02
file3.pdf
file4.pdf

etc

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

/new-files
file1.pdf
file2.pdf
file3.pdf
file4.pdf

Может кто-нибудь сказать, пожалуйста, лучший способ сделать это с помощью bash сценария? В основном я хотел бы прочитать каталог new-files и затем заменить любые совпадающие имена файлов в других папках.

Заранее спасибо за любую помощь!

Ответы [ 2 ]

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

Предполагая, что каталог 'new-files' и все деревья каталогов, содержащие файлы PDF, находятся в текущем каталоге, попробуйте этот код Shellcheck -clean Bash:

#! /bin/bash -p

find . -path ./new-files -prune -o -type f -name '*.pdf' -print0 \
    |   while IFS= read -r -d '' pdfpath; do
            pdfname=${pdfpath##*/}
            new_pdfpath=new-files/$pdfname
            if [[ -f $new_pdfpath ]]; then
                printf "Replace '%s' with '%s'\n" "$pdfpath" "$new_pdfpath" >&2
                # cp -- "$new_pdfpath" "$pdfpath"
            fi
        done
  • -path ./new-files -prune в команде find останавливает поиск в каталоге 'new-files'.
  • -o в команде find вызывает следующий тест и действия для попытался после проверки «новых файлов».
  • См. BashFAQ / 001 (Как я могу прочитать файл (поток данных, переменную) построчно (и / или поле за полем) )?) для объяснения использования опции -print0 для find и while IFS= read -r -d '' .... Короче говоря, код может обрабатывать произвольные пути к файлам, в том числе с пробелами и символами новой строки в них.
  • См. Удаление части строки (BashFAQ / 100 (Как мне манипулировать строками в bash?)) для объяснения ${pdfpath##*/}.
  • Мне не ясно, хотите ли вы скопировать или переместить новый файл, чтобы заменить старый файл, или сделать что-то еще. Запустите код так, как он есть, чтобы проверить, правильно ли он определяет правильные замены. Если вас это устраивает, раскомментируйте строку cp и измените ее, чтобы сделать что-то другое, если вы этого хотите.
  • -- в команде cp защищает от аргументов, начинающихся с da sh символы интерпретируются как опции. В этом случае это не нужно, но я всегда использую его, когда аргументы начинаются с переменных (или других) расширений, поэтому код останется безопасным, если его использовать в других контекстах.
0 голосов
/ 11 февраля 2020

Я думаю, что для этого требуется массив bash.

#!/usr/bin/env bash

# Make an associative array
declare -A files=()

# Populate array as $files[file.pdf]="/path/to/file.pdf"
for f in 20*/*/*.pdf; do
  files[${f##*/}]="$f"
done

# Step through files and replace
for f in new-files/*.pdf; do
  if [[ ! -e "${files[${f##*/}]}" ]]; then
    echo "ERROR: missing $f" >&2
    continue
  fi
  mv -v "$f" "${files[${f##*/}]}"
done

Обратите внимание, что для ассоциативных массивов требуется bash версия 4 или выше. Если вы используете собственный bash на Ma c, это не будет работать как есть.

Обратите внимание, что если вы удалите continue в последних строках, то mv команда НЕ будет безопасно перемещать файлы, которые не существуют в каталогах с датой ha sh, поскольку цель не известна.

Если вы хотели получить дополнительную защиту, вы можете использовать test -nt или друзей, чтобы подтвердить, что обновление происходит в правильном направлении.

...