Сообщение об ошибке сценария копирования CSV в bash

У меня есть этот скрипт, который копирует файлы, перечисленные в csv, рекурсивно из основной папки. Копирующий аспект скрипта работает отлично. Однако теперь я хочу добавить некоторые функции обнаружения ошибок. Цикл «if», который я добавил ниже, не работает, как хотелось бы. Я добавил фальшивый файл в список csv для тестирования, и сценарий сообщает, что все файлы скопированы успешно, хотя один из файлов не существует. Может ли кто-нибудь предложить, как я могу заставить скрипт сообщать о файлах, которые он не смог найти / скопировать из csv и указать имена файлов? EDIT ** Поскольку в CSV есть 4000+ файлов, я хотел бы, чтобы сценарий распечатывал сводку любых ошибок копирования в конце скрипта, а не для каждого файла, скопированного во время процесса. Это облегчит определение / обобщение любых вопросов.

while IFS=, read -r file rest do find $sourcefolder -name "${file}" -exec cp '{}' $destfolder \; done < $csv if [ $? -eq 0 ] then echo "All files from CSV copied succesfully" else "File from CSV not copied as not found" fi 

Код ошибки, возвращаемый find , не имеет никакого отношения к тому, были ли найдены файлы. Он вернет код ошибки только в том случае, если сама команда не запускалась. То, что вы ищете, это что-то вроде:

 while IFS=, read -r file rest do find $sourcefolder -name "${file}" -exec cp '{}' $destfolder \; ## Check if the file was copied [[ -e "$destfolder/$file" ]] || echo "File $file was not copied" done < "$csv" echo "Finished" 

Таким образом, сценарий расскажет вам о любых файлах, которые не были успешно скопированы.

Если вы хотите только напечатать ошибку в конце скрипта, вы можете сохранить неправильные имена файлов в переменной и распечатать их после завершения цикла:

 while IFS=, read -r file rest do find "$sourcefolder" -name "$file" -exec cp '{}' "$destfolder" \; ## Check if the file was copied [[ -e "$destfolder/$file" ]] || badfiles=$(printf "%s\n%s" "$file" "$badfiles") done < "$csv" ## Check if all the files were correctly copied if [[ -z "$badfiles" ]]; then echo "All files were succesfuly copied." else printf 'Some files were not copied:\n%s\n' "$badfiles" fi 

Вы также можете расширить это, чтобы избежать перезаписи файлов с тем же именем:

 while IFS=, read -r file rest do find "$sourcefolder" -name "$file" -print0 | while IFS= read -d '' -r filepath; do c=""; while [[ -e "$destfolder/$file$c" ]]; do ((c++)) done cp "$filepath" "$destfolder/$file$c" done ## Check if the file was copied [[ -e "$destfolder/$file" ]] || badfiles=$(printf "%s\n%s" "$file" "$badfiles") done < "$csv" ## Check if all the files were correctly copied if [[ -z "$badfiles" ]]; then echo "All files were succesfuly copied." else printf 'Some files were not copied:\n%s\n' "$badfiles" fi 

Это не удастся, если имена файлов в вашем csv могут содержать символы новой строки. Если это возможно, измените первый цикл while на:

 while IFS= read -d"," -r file rest; do ... 

Обратите внимание, однако, что это произойдет, если какая-либо строка csv не содержит ничего, кроме имени файла (поэтому нет запятой). Вы не можете иметь его в обоих направлениях, если вы можете иметь строки без запятых, используйте 1-ю версию, и если вы можете иметь имена файлов с символами новой строки, используйте вторую.

  1. Ваша петля неверна, поскольку вы ничего не делаете с rest

  2. Как предложил terdon , проверьте после каждой копии, а не один раз после цикла

  3. Отмените проверку файла, для правильного комментария
  4. И прислушайтесь к предупреждению о тердоне , если у вас есть одинаковые именованные файлы в исходном дереве, вы получите только одну копию в месте назначения.

Попробуй это,

 while read -d, -r file do find $sourcefolder -name "${file}" -exec cp '{}' $destfolder \; ## Check if the file was copied [[ ! -e "$destfolder/$file" ]] && echo "File $file was not copied" done < "$csv" echo "Finished" 

Обновить:

Это решение работает, если ваш CSV подобен этому

 fileA,fileB,fileC,fileD, ... 

Однако, поскольку вы говорите, что решение terdon работает, ваш файл должен выглядеть так:

 fileA,valueA1,valueA2,valueA3 fileB,valueB1,valueB2,valueB3 fileC,valueC1,valueC2,valueC3 fileD,valueD1,valueC2,valueD3 

а оставшаяся строка после имени файла просто отбрасывается.