80 GB のファイルを含むフォルダーから 30 GB のファイルを移動するにはどうすればよいですか?

80 GB のファイルを含むフォルダーから 30 GB のファイルを移動するにはどうすればよいですか?

500 本以上のビデオが入ったフォルダーがあり、フォルダーのサイズは約 80 GB です。

30GB のビデオを別のフォルダーに移動したいのですが、どうすればよいですか?

ターミナルを使用しているため、GUI をインストールできません。

答え1

選択的に(自動的に

これを実行できるコマンドラインツールを私は知りません...しかし、次のようにスクリプトを使用して、特定の合計サイズが移動されるまでファイルを移動することができます(スクリプトは1回だけ実行してください...もう一度実行すると、残りのファイルから指定されたサイズが再度移動されます):

#!/bin/bash

sourc_dir="/path/to/directory" # Set the path to the source directory "no trailing /"
dest_dir="/path/to/directory" # Set the path to the destination directory "no trailing /"
move_size="30" # Set the total size of files to move in Gigabytes
 
# Don't edit below this line
move_size=$(( move_size * 1000000 ))
current_size=$(du -sk "$sourc_dir" | awk '{printf "%d", $1}')
remaining_size=$(( current_size - move_size ))

for f in "$sourc_dir"/*; do
  [ -f "$f" ] || continue
  new_size=$(du -sk "$sourc_dir" | awk '{printf "%d", $1}')
  (( new_size <= remaining_size )) && exit
  mv -n -- "$f" "$dest_dir"/
  done

あるいはワンライナーでも(スクリプトファイルは不要) をターミナルで次のように実行できます。

for f in /path/to/source/*; do [ -f "$f" ] || continue; (( size >= (30*(1000**3)) )) && break || (( size += $(stat --printf "%s" "$f") ))  && mv -n -- "$f" /path/to/destination/; done

unset size同じシェルインスタンスで再実行できるようにしたい場合があります。

選択的に(手動で

ファイル名、サイズ、タイプなどに基づいて、検索ツールからいつでもシェル パターンまたはパイプを指定できます。

または、より便利な方法として、例えばよく知られた機能豊富なコンソールベースのファイルマネージャのように、複数のファイル選択をサポートするファイルマネージャを使用することもできます。GNU ミッドナイトコマンダーこれは Ubuntu の公式リポジトリから入手でき、次のようにインストールできます。

sudo apt install mc

実行するには、次のように入力しmcてクリックしますEnter...すると、キーボードのキーを使用して複数のファイルを選択できる操作可能な UI が表示されますInsert...次のように、選択したファイルの合計サイズとその数をリアルタイムで確認できます。

ここに画像の説明を入力してください

移動するすべてのファイルの選択が完了したら、F6キーボードのキーを押して移動/名前変更ダイアログを開き、移動先ディレクトリを入力して、[< OK >]次のように選択したファイルを一度に移動することを選択します。

ここに画像の説明を入力してください

あるいは、あまり知られていない機能の少ないものでも超高速ファイルマネージャー:-) ... 興味深いことに、 ... 複数ファイルの選択をサポートしていますが、選択したファイルの合計サイズを確認できるようにするには、少しカスタマイズする必要があるかもしれません。たとえば、簡単なパッチとして、ソース ファイルのbash次の行を変更できます。159fff

local mark_ui="[${#marked_files[@]}] selected (${file_program[*]}) [p] ->"

これに:

local mark_ui="[${#marked_files[@]}] $(for f in "${marked_files[@]}"; do (( tsize += $(stat --printf "%s" "$f") )); done; tsize=$((tsize/(1000**2))); printf '[%d M]' "$tsize";) selected (${file_program[*]}) [p] ->"

次に、そのファイルを次のように実行します(インストール不要):

bash fff

または、次のように使用方法のヘルプを表示します。

bash fff -h

その後は、ソースディレクトリに移動して、m小文字) キーボードのキーを次のように押します。

ここに画像の説明を入力してください

ファイルの選択が完了したら、宛先ディレクトリに移動し、p小文字) キーボードのキーを押します。

答え2

代替案はこちらラファの考え方は、duすべてのファイルに対してディレクトリ全体の を必要としません。代わりに、stat各ファイルに対してを実行します。一度、を使用してfindサイズ-printf %sを取得し、%p移動するファイルへのパスを取得します。

#!/bin/bash

src='foo'
dest='bar'

# 30GB in bytes to move:
(( bytestomove=30*(1000**3) ))
movedbytes=0

while IFS=$'\t' read -r -d '' bytes file
do
    # if we already moved enough, break out
    (( movedbytes >= bytestomove )) && break;

    # try to move it, break out if it fails
    mv -n -- "$file" "$dest" || break

    # successfully moved, add bytes to movedbytes
    (( movedbytes += bytes ))
done < <(find "$src" -type f -printf "%s\t%p\0")

(( movedmegs=movedbytes/(1000**2) ))
printf "Moved %d MB\n" $movedmegs

答え3

@TedLyngmo は、私が最初に提示した tar ソリューションは、ファイルをコピーするだけで、移動しないことを指摘しました。この区別は、次の 2 つの理由で重要です。

  1. コピーの場合、ソース ファイルは残りますが、移動の場合、ソース ファイルはソースの場所に存在しなくなります。
  2. この質問の場合もそうであるように、ファイルが同じファイルシステム内で移動された場合、mvソース ファイルを新しい場所に再リンクするだけで、コンテンツはまったくコピーされません。これは通常、特に大きなファイルの場合、コピーよりも大幅に高速になります。

移動シナリオ

tar最初に提示したコピー シナリオの概念を使用して、見つかった最初の 30 GB のファイルのみを含むファイル リストを作成しtar、それらのファイルのみを移動することができます。

#!/bin/bash

# Convert human-readable number, e.g. 1M, 30G to number of 1024 byte blocks 
limit=$(numfmt --from=auto $1 --to-unit 1024)
src_dir=$2
dest_dir=$3

mkdir $dest_dir
filelist=$(readlink -f $(mktemp -p $dest_dir))

# create a list of files to be moved.  tar -v outputs filenames to stdout, and 
# the dest archive is /dev/null
tar -v -L $limit -F false -c -f /dev/null -C $src_dir . > $filelist 2> /dev/null
tar_result=$?
if [ "$tar_result" = 2 ]; then
    echo "$1 limit was hit - some unmoved files will remain in $dest_dir"
else
    echo "All files will be moved"
fi

pushd $dest_dir > /dev/null
abs_dest_dir=$PWD
# create directories in the destination
grep '/.*/$' $filelist | xargs mkdir -p
popd > /dev/null

pushd $src_dir > /dev/null
# create hard links in the destination
grep -v '/$' $filelist | xargs cp -l --parents -t $abs_dest_dir
# unlink source files
grep -v '/$' $filelist | xargs rm
# remove source directories in reverse order, if they are empty
grep '/.*/$' $filelist | tac | xargs rmdir --ignore-fail-on-non-empty
popd > /dev/null

rm $filelist

これは私が望むよりも複雑です:

  • mv複数のファイルのソースと宛先のパスをあまり制御できないため(特に、cpの--parentsオプションに類似するものはありません)、ファイルの移動は、宛先の場所にハードリンクを作成し、ソースファイルのリンクを解除することによって実現されます。

  • ソース ディレクトリには、移動するエントリと移動しないエントリが混在しているため、ディレクトリは、単純に (すべてのコンテンツとともに) 移動するのではなく、宛先で再作成する必要があります。そのため、ファイルを移動する前に適切な宛先ディレクトリが作成され、ファイルを移動した後に対応するソース ディレクトリが空の場合は削除されます。

注意点

  • tar -v1 行につき 1 つのファイル エントリを出力します。パス名に改行などの特殊文字が含まれている場合、これは完全に失敗します。ソース パス名が適切に命名されていることを願います。

  • ストリームには実際のコンテンツだけでなくメタデータ (ファイル名、タイムスタンプなど) も含まれており、これらはすべて 30 GB の制限の対象となるため、実際のファイル データは 30 GB より少し少なく移動されます。

  • ここでは KB と kb を少し大雑把に扱っています。パラメータは-L1024 バイト単位で機能するため、実際には tar ストリームの移動は 3,072,000,000 バイトに制限されます。数値は適宜調整してください。

  • filelist.txt が現在のディレクトリに作成されます。これには書き込み権限が必要ですが、移動操作には書き込み権限が必要なので、これは当然のことです。

コピーシナリオ

tarを使用してフォルダをストリームに変換し、tar再度使用してストリームを新しい場所のファイルに戻すことができます。最初のtar使用では-L、新しいテープを要求する前に、「テープ長」を 3000000 KB に制限します。 各「テープ」の後にtar-F を実行します。はエラーを返すため、最初の「テープ」、つまり 30GB の後に転送が停止します。すべてのデータを tar の 2 回の呼び出しで処理する方が、bash ループですべてのファイルをループするよりも高速です。falsefalse

mkdir dest.dir
tar -cv -L 3000000 -F false -C src.dir . | tar -x -C dest.dir/

これにより、30 GB の制限に達するまでファイルがコピーされ、その後、tar次のエラーが発生します。

tar: Unexpected EOF in archive
tar: Unexpected EOF in archive
tar: Error is not recoverable: exiting now
tar: ‘false’ command failed
tar: Error is not recoverable: exiting now

tar制限に達したときに転送中だったファイルは転送されず、宛先にまったく書き込まれません。

注意点

  • ストリームには実際のコンテンツだけでなくメタデータ (ファイル名、タイムスタンプなど) も含まれているため、実際のファイル データは 30 GB より少し少なくコピーされますが、これらはすべて 30 GB の制限の対象となります。

  • ここでは KB と kb を少し大雑把に扱っています。パラメータは-L1024 バイト単位で機能するため、実際には tar ストリームの転送が 3,072,000,000 バイトに制限されます。必要に応じて数値を調整してください。


この回答の以前の編集では、find-cpio-head-cpio を使用し、次に tar-head-tar を使用しました。現在提示されている tar-tar ソリューションで十分なはずですが、他のソリューションに興味がある場合は編集履歴を調べてください。

答え4

ファイルがあるフォルダに移動します:

cd SOURCE_FOLDER

そのフォルダ内のファイルのリストを作成する

ls > list.txt

任意のエディターで編集し、移動したくないファイルを削除します。結果を保存すると、list.txt には移動するファイルのみが含まれるようになります。次に、list.txt ファイルから各行を読み取り、そのファイルを宛先ディレクトリに移動するこの簡単なスクリプトを実行します。

while IFS= read -r line; do mv "$line" ../DESTINATION_DIRECTORY/"$line"; done < list.txt

関連情報