Поскольку в вопросе указывается переименование и копирование, а не переименование и перемещение файлов, решение должно предположительно убедиться, что файлы из исходного каталога не продублированы в месте назначения.Это усложняет решение.
Сценарий не может просто проверить наличие исходного файла в месте назначения, поскольку он был переименован как часть перемещения.Выполнение cmp
или diff
, вероятно, приводит к расточительному использованию ресурсов, особенно если сравниваемые файлы представляют собой большие дампы базы данных (на что указывает расширение .sql).
В приведенном ниже решении я добавилфайл манифеста, чтобы отследить, какие файлы были скопированы, но если бы я создавал это для себя, мне не понравился бы такой подход.Если файл манифеста был случайно удален или отредактирован, скрипт потеряет отслеживание того, какие файлы уже были скопированы, и при следующем запуске все файлы будут скопированы.Последовательная индексация имен файлов в каталоге назначения будет исключена.Если возможно, я думаю, что было бы лучше:
- Переименовать исходные файлы, чтобы отразить их скопированный статус, после чего исключить эти файлы из операции копирования
- Переименовать и переместить файлыот исходного каталога до места назначения
Обратите внимание, что при выполнении числовых сравнений bash видит числа с ведущими нулями как восьмеричные.Вы можете удалить начальные нули при извлечении числа для сравнения, но я использовал $((10#$foo))
в условиях теста, чтобы указать десятичные числа.Я думаю, что это испортило подсветку синтаксиса Переполнения стека - что неправильно трактует текст после #
в 10#
как комментарий.
#!/bin/bash
# Set source and destination paths
readonly SRC=src
readonly DEST=dest
readonly COPY_MANIFEST="${SRC}"/copied.txt
# $COPY_MANIFEST will keep track of which files have been copied
[[ -f "$COPY_MANIFEST" ]] || touch "$COPY_MANIFEST"
# Get the highest index in destination directory from the file numeric prefix
highest=0
for file in $DEST/*; do
base=$(basename ${file})
index=$(echo $base | sed 's/[^0-9]//g')
# Compare numbers. Convert to decimal format because leading zeros denote octal numbers
[[ $((10#$highest)) -le $((10#$index)) ]] && highest=$index
done
# Rename and copy files from source to destination
for original in ${SRC}/*; do
previously_copied=false
# Don't process the manifest file
[[ ${original} = $COPY_MANIFEST ]] && continue
# If the source directory is empty, exit early
[[ -f "$original" ]] || { echo "No source files in ${SRC}"; exit;}
# Check the file has not already been copied - uses a manifest file rather
# than using tools like cmp or diff to check for duplicate files.
while read line; do
if [[ "${original}" = "${line}" ]]; then
echo "${original} has already been renamed and copied."
previously_copied=y
fi
done < "$COPY_MANIFEST"
[[ $previously_copied = y ]] && continue
# Get the base name of the file
name=$(basename ${original})
# Original question asks that all files greater than v000_179_crt_table_stat_flg.sql are copied.
# If this requirement is not needed, the next 2 lines can be removed
num=$(echo "$name" | sed 's/V[0-9]*_\([0-9]*\).*/\1/g')
[[ $((10#$num)) -le $((179)) ]] && { echo "Not eligible"; continue; }
# Build the new filename and copy
# Get rid of the prefix, leaving the descriptive name
name=${name#V[0-9]*_[0-9]*_}
highest=$(( 10#$highest + 1 ))
new_name=V${highest}__${name}
cp ${original} ${DEST}/${new_name}
# Update the manifest to prevent repeat copying
echo ${original} >> $COPY_MANIFEST
done