Файлы «перезаписаны», пространство все еще занято, они потеряны?

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

dirs=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
shopt -s nocasematch

for file in *
do
    for dir in "${dirs[@]}"
    do

     if [ -d "$file" ]; then
      echo 'this is a dir, skipping'
      break
     else
      if [[ $file =~ ^[$dir] ]]; then
       echo "----> $file moves into -> $dir <----"
       mv "$file" "$dir"
       break
      fi
     fi
  done
done

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

----> a1.ts moves into -> A <----
----> a2.ts moves into -> A <----
----> a3.ts moves into -> A <----
----> a4.ts moves into -> A <----
----> a5.ts moves into -> A <----
----> c1.ts moves into -> C <----
----> c2.ts moves into -> C <----
----> c3.ts moves into -> C <----
----> c4.ts moves into -> C <----
----> c5.ts moves into -> C <----

Я, к счастью, остановил процесс (CTRL + C), как только заметил, что все идет не так, как задумано, и не пошел через всю папку.

Итак, теперь у меня есть файлы A и C, размер которых не превышает Гб, и, судя по всему, это ОДНО видео.

В общем объеме использования самой папки на диске не хватает 50 ГБ, но общее дисковое пространство компьютера осталось прежним. Заставить меня думать, что файлы не удалены?

Любая помощь приветствуется, спасибо:)

Редактировать: файлы фактически исчезли, только последний файл, который будет записан остается, все, что потребовалось некоторое время, чтобы обновить информацию об использовании диска .. Мораль истории, запустите свои сценарии на фиктивных файлах раньше!

11
задан 14 September 2019 в 14:18

6 ответов

Я думаю, что это - проблема: необходимо было создать каталоги A, B, C... Z. Если Вы сделали, mv команда должна была переместить файлы в те каталоги.

Но в противном случае mv управляйте перемещает файлы в файлы с теми именами, A, B, C..., и я думаю, что это - то, что Вы сделали.

Для создания сценария оболочки более безопасным необходимо заставить его создать каталоги (если они уже не там) перед запуском перемещения.

dirs=(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)

for dir in "${dirs[@]}"
do
 mkdir -p $dir
done

Если Вы хотите вещи стать еще более в безопасности, можно также использовать mv с -i опция

   -i, --interactive
          prompt before overwrite
15
ответ дан 23 November 2019 в 03:52

@Sudodus уже объяснил, что пошло не так, как надо, но здесь является более простой версией Вашего сценария в следующий раз:

for letter in {a..z}; do 
    dir=${letter^}
    mkdir -p -- "$dir" 
    mv -- "$letter"* "${letter^^}"* "$dir"/
done

Объяснение

  • for letter in {a..z}; do: {a..z} расширяется до всех строчных букв между a и z:

    $ echo {a..z}
    a b c d e f g h i j k l m n o p q r s t u v w x y z
    

    Таким образом, это выполнит итерации по всем строчным буквам, сохраняя каждого как $letter.

  • dir=${letter^} : синтаксис ${var^^} возвращает содержание переменной $var с первым символом в верхнем регистре (так как это только имеет один символ, это - все, которое нам нужно). Так, если $letter a, затем ${letter^^} A, и поэтому $dir будет прописная версия тока $letter.

  • mkdir -p -- "$dir" : создайте каталог. Если это уже существует, ничего не сделайте (-p). -- показывает конец опций и полезен для защиты от имен, запускающихся с -.
  • mv -- "$letter"* "${letter^}"* "$dir" : переместите каждый файл (или каталог) к соответствующей цели.

Проблема с этим, то, что она также переместит любые каталоги, которые Вы можете иметь. Это не переместит целевые каталоги, потому что или они еще не существуют, или Вы попытаетесь переместить их в себя, но будут перемещены любые существующие директора, которые не являются целевым dir.

Если это - проблема, необходимо будет сделать что-то вроде этого:

for file in *; do 
    if [[ ! -d "$file" ]]; then 
        letter="${file:0:1}"
        dir="${letter^}"
        mkdir -p -- "$dir"
        mv -- "$file" "$dir"/
    fi
done
7
ответ дан 23 November 2019 в 03:52

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

Очень простой вид:

#!/bin/bash

videos=./videos
sorted=./sorted

# sort types link,move.
sort_type=link

find "$videos" -maxdepth 1 -type f \
   \( -name '*.avi' -o -name '*.mkv' -o -name '*.mp4' \) -print0 |

while IFS= read -r -d ''; do

    b=$(basename "$REPLY")
    c=${b::1}

    case $c in
        [a-zA-Z]) label=${c^} ;; [0-9]) label="0-9" ;; *) label="_" ;;
    esac

    [[ ! -d "$sorted/$label" ]] && mkdir -p "$sorted/$label"

    if [[ -L $sorted/$label/$b ]] || [[ -e $sorted/$label/$b ]]; then
        echo "File/link: '$b' exists, skipping."
        continue
    fi

    case $sort_type in
        link)
            ln -rfst "$sorted/$label" -- "$REPLY"
            ;;
        move)
               mv -t "$sorted/$label" -- "$REPLY"
            ;;
    esac
done
4
ответ дан 23 November 2019 в 03:52

Охраняйте в своем .bashrc:

alias mv="mv -n --backup=numbered"
2
ответ дан 23 November 2019 в 03:52

Для записи, некоторые способы остановиться mv от перезаписи существующих файлов:

  • Если Вы хотите переместиться в каталог, добавьте наклонную черту к цели, т.е. использование mv "$file" "$dir"/ вместо mv "$file" "$dir". Если $dir не существует или не каталог, mv будет жаловаться:

    $ touch a
    $ mv a z/
    mv: cannot move 'a' to 'z/': Not a directory
    $ touch z
    $ mv a z/
    mv: failed to access 'z/': Not a directory
    

    Это, кажется, делает системный вызов rename("a", "z/"), таким образом, это должно быть безопасно от time-of-check-to-time-of-use уязвимостей, в случае, если кто-то обрабатывает тот же набор файлов одновременно.

  • С другой стороны, используйте mv -t "$dir" "$file". Снова, это будет жаловаться если $dir не каталог.

  • Используйте -n опция предотвратить перезаписывающие существующие файлы:

    -n, --no-clobber
        do not overwrite an existing file
    

    Это не будет мешать ему переименовать первый файл, но это затем не повредит его с другими.

    Это, кажется, называет плоскость rename(), таким образом, это могло бы быть не быть безопасным с одновременной обработкой. (Существует renameat2() это поддерживало бы флаг для предотвращения перезаписи.)

2
ответ дан 23 November 2019 в 03:52

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

  • Одна или несколько 'жестких ссылок' на те же файлы существуют в другом месте в файловой системе
  • Один или несколько процессов имеют открытый файл

Файловые системы Unix позволяют больше чем одной записи каталога относиться к тому же самому содержанию файла. Это называют 'жесткой ссылкой'. Можно создать жесткие ссылки с ln команда, без общего -s (мягкая/символьная) опция. Целая по крайней мере одна жесткая ссылка существует к содержанию файла, она не будет снова использована файловой системой.

(Примечание стороны, полномочия обычно относятся к содержанию файла, не к записи каталога. Поэтому обычный пользователь может иногда удалять файл, принадлежавший root, но не пишут в него. Удалить операция изменяет папку, не сам файл.)

Файловая система также не снова использует содержание файла, целый по крайней мере один процесс имеет открытый файл. Даже если никакая запись каталога не будет существовать, то файловая система не будет полагать, что пространство свободно, пока никакие процессы не будут иметь его открытый. Файл может быть восстановлен с виртуальной файловой системы /proc/<pid>/fd root пока файл остается открытым. (Спасибо @fluffysheap.)

1
ответ дан 23 November 2019 в 03:52

Другие вопросы по тегам:

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