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


11

だから、私は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はGb未満で、その見た目では1つのビデオです。

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

どんな助けも感謝します、ありがとう:)

編集:ファイルは実際にはなくなり、最後に書き込まれるファイルのみが残ります。ディスク使用情報が更新されるまでに少し時間がかかりました。


3
そして、ディレクトリが名前のなかったABというようにスクリプトを実行する前に存在していましたか?そうでない場合は、ファイルの名前を変更します。名前がで始まるaか、名前Aがに変更されたすべてのファイルAは、最後に名前が変更されたファイルのみが生き残り、他は上書きされます。変数を呼び出すdirことはディレクトリを作成しません!
mook765

2
それも同様にそれを解釈した方法です。「最後に名前を変更したファイルは生き残った」ha。ディレクトリが存在しなかったので、事前にそれぞれに「タッチ」を追加する必要がありました。明確化してくれてありがとう
私はTI電卓です

4
「..話の教訓、前に模擬ファイルでスクリプトを実行してください!」の+1
sudodus

4
このような問題を回避するためのヒント:を使用mv "$file" "$dir/"し、末尾に/; $dir存在しない場合はmv、名前$fileを変更する代わりにエラーになります$dir。とも検討mv -iしてくださいmv -n。そしてmkdir -p、適切な措置のために、常に移動する前に行動してください。
-marcelm

3
@sudodusさらに良いモラル、「常にデータをバックアップしてください!」。
ジョンベントレー

回答:


15

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

1
スクリプトを複数回実行する場合の競合を避けるためにtouch、追加することは良い代替mkdirでしょうか?
私はTI電卓です

2
touch名前が存在しない場合、ファイルを作成します。そのため、この場合、あなたが望むことはしません。mkdir -pスクリプトを数回使用して処理できます。
sudodus

6
mvより安全にするためのもう1つの簡単な方法は、ターゲットがディレクトリの場合、ターゲット名に末尾のスラッシュを追加する習慣をつけることですmv "$file" "$dir/"
。– steeldriver

7

@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大文字の最初の文字を含む変数の内容を返します(これには1文字しかないため、必要なのはこれだけです)。もしそうであれば、$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

違いは何だ${letter^}${letter^^}、彼らが同じなら、なぜ使用${letter^^}の代わりには$dir
ファンドモニカの訴訟

1
@NicHartley ${var^}は最初の文字のみを${var^^}大文字にし、すべての文字を大文字にします。$letter文字が1つしかないため、ここでは違いはありません。
テルドン

これは完璧な答えです。ただし$dirmvコマンドにディレクトリスラッシュを追加して、注意を払う必要がある場合を除きます。(現在の形では、それは失敗します単一文字の大文字の名を持つファイル既に存在)
スティグヘメル

@StigHemmerおっと、はい、確かに。非常に良い点、ありがとう。回答を編集しました。
テルドン

4

すべてのファイルを多数の反復を作成する辞書配列と照合する代わりに、ファイルをパターンと照合できます。

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

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

たぶん私はそれを間違えたが、それは明確に機能しなかった、10個のファイルを失った笑。REPLYの部分を十分に把握できていませんか?意図は何ですか残っているのは(フォルダABCD内に... ...)エイリアスファイル自体が指すエイリアスです.. thaエイリアス
私はTI電卓です

引数が指定されていない場合、read組み込みコマンドによって読み取られた入力行に設定されたREPLY。
bac0n

それでは最後にln -rfst "$ sorted / $ label"-"$ REPLY"を実行します。mvで移動した場合、エイリアスはなぜですか?
私はTI電卓です

デフォルトとして、それはあなたがそれらをmvをしたい場合は、コメントを外し、「移動動画」とコメント「リンク・ビデオ」(私はシンボリックリンクがそれほど怖いと思います)に必要な、あなたのソートされたディレクトリに「動画」ディレクトリからのリンクを作成します
bac0n

...同時に両方ではありません。
bac0n

2

.bashrcの保護:

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

1
@ザンナ、ありがとう!引用符を追加しました。

(初心者であること)を確認するための質問はほとんどありません。.zshrcファイルの追加も有効です(ZSHを使用している場合)。で男MV述べています-n Do not overwrite an existing file. (The -n option overrides any previous -f or -i options.)ので、それは問題ではないということ-nタグは、タグを次の前になりますか?番--backup =各権利のダブルを作成しますが、いないビット行き過ぎ(と宇宙エネルギー/消費する)特級大きなビデオファイルを扱う(話テラバイト)があります。ありがとう!
私はTI電卓です

2

記録のために、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

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

    これはplainを呼び出すようですrename()ので、同時処理では安全ではないかもしれません。(renameat2()上書きを防ぐためのフラグをサポートするものがあります。)


1

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

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

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

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

また、少なくとも1つのプロセスがファイルを開いている限り、ファイルシステムはファイルコンテンツを再利用しません。ディレクトリエントリが存在しない場合でも、ファイルシステムは、プロセスが開いていない限り、空き領域を考慮しません。ファイルは復元することができる仮想ファイルシステムから/proc/<pid>/fdrootある限り、ファイルが開いたままで。(@fluffysheapに感謝します。)


1
ファイルが開いた状態でプロセスが発生した場合は、/ proc / <pid> / fdで検索して回復できます。superuser.com/questions/283102/…を
fluffysheap
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.