web-dev-qa-db-ja.com

「上書きされた」ファイル、まだ占有されているスペース、それらは失われていますか?

そのため、私は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)。

これで、これらのファイルACを取得しました。これらはGB未満であり、見た目は1つのビデオです。

フォルダー自体の合計ディスク使用量に含まれていない50Gbがありますが、コンピューターの全体的なディスク領域は同じままです。ファイルが削除されていないと思いますか?

感謝します、ありがとう:)

編集:ファイルは実際になくなり、書き込まれる最後のファイルのみが残ります。ディスク使用情報が更新されるまでに少し時間がかかりました..話の教訓、 !の前にモックファイルでスクリプトを実行します

11

これが問題だと思います。ディレクトリ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
sudodus

@ 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}は、azの間のすべての小文字に展開されます。

    $ 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の内容を最初の文字を大文字にして返します(これにはone文字しか含まれていないため、これで十分です)。したがって、$letteraの場合、${letter^^}Aであるため、$dirは現在の$letterの大文字バージョンになります。

  • mkdir -p -- "$dir":ディレクトリを作成します。既に存在する場合は、何もしません(-p)。 --オプションの終わりを示す であり、-で始まる名前から保護するのに役立ちます。
  • mv -- "$letter"* "${letter^}"* "$dir":すべてのファイル(またはディレクトリ)を関連するターゲットに移動します。

これの問題は、あなたが持っているかもしれないどんなディレクトリも移動することです。ターゲットディレクトリはまだ存在しないか、それらを自分自身に移動しようとするため、ターゲットディレクトリは移動しませんが、ターゲットディレクトリではない既存のディレクトリは移動されます。

それが問題である場合は、次のようなことを行う必要があります。

for file in *; do 
    if [[ ! -d "$file" ]]; then 
        letter="${file:0:1}"
        dir="${letter^}"
        mkdir -p -- "$dir"
        mv -- "$file" "$dir"/
    fi
done
7
terdon

多くの反復を作成するディクショナリ配列に対してすべてのファイルをチェックする代わりに、パターンに対してファイルを照合できます。

非常に基本的な並べ替え:

#!/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
bac0n

.bashrcの保護:

alias mv="mv -n --backup=numbered"
2
user996146

参考までに、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/")を作成しているようです。そのため、誰かが同じファイルセットを同時に処理している場合に備えて、チェック時刻から使用時刻までの脆弱性から安全である必要があります。 。

  • または、_mv -t "$dir" "$file"_を使用します。繰り返しになりますが、_$dir_がディレクトリでない場合は文句を言うでしょう。

  • 既存のファイルを上書きしないようにするには、_-n_オプションを使用します。

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

    最初のファイルの名前を変更することはできますが、他のファイルと一緒にゴミ箱に移動することはありません。

    これは単純なrename()を呼び出すように見えるため、同時処理では安全ではない可能性があります。 (上書きを防止するフラグをサポートする renameat2() があります。)

2
ilkkachu

明らかにあなたには当てはまりませんが、これを行うことができ、ファイルを失わない可能性があります。これには、次の2つの条件のいずれかが当てはまる必要があります。

  • 同じファイルへの1つ以上の「ハードリンク」がファイルシステムの別の場所に存在する
  • 1つ以上のプロセスがファイルを開いています

Unixファイルシステムでは、複数のディレクトリエントリがまったく同じファイルコンテンツ。これは「 ハードリンク 」と呼ばれます。 lnコマンドを使用してハードリンクを作成できますなし共通-s(ソフト/シンボリック)オプション。ファイルコンテンツへのハードリンクが少なくとも1つ存在する限り、それはファイルシステムによって再利用されません。

(注意:アクセス許可は通常、ディレクトリエントリではなくファイルコンテンツに適用されます。これが、通常のユーザーがrootが所有するファイルを削除できるが、書き込みできない場合がある理由です。削除操作により、フォルダが変更されます。 、ファイル自体ではありません。)

また、ファイルシステムは、少なくとも1つのプロセスがファイルを開いている限り、ファイルの内容を再利用しません。ディレクトリエントリが存在しない場合でも、ファイルシステムは、開かれているプロセスがなくなるまで、空き領域とは見なしません。ファイル リカバリ可能 仮想ファイルシステムから/proc/<pid>/fd by rootファイルが開いたままである限り。 (@fluffysheapに感謝します。)

1
wberry