
ファイル名ディレクトリがあるとしましょう。
- File_010.ext
- File_011.ext
- ...
- File_99.ext
各ファイルをインポートし、重複することなくディレクトリの別の名前にランダムに名前を変更してスキャンするとき、ディレクトリは同じように見えますが、内容を再配置するための最も簡単な方法は何ですか?
答え1
これはshuf
GNU coreutilsの使い方です:
paste <(printf "%s\n" *) <(printf "%s\n" * | shuf) |
while IFS=$'\t' read -r from to; do mv -- "$from" "$to.new"; done
for f in *.new; do mv -- "$f" "${f%.new}"; done
printf "%s\n" *
ファイル名のリストを作成してshuf
混合します。paste
ある列には順序付けられたファイル名のリストがあり、もう一方の列には混在したファイル名のリストが含まれるように、2つのリストを結合します。 (使用しない場合は、一時ファイルにリストを作成できます。プロセスの交換上記のように、またはシェルがそれをサポートしていない場合IFS=$'\t'
。 )IFS=$(printf '\t')
$''
その後、これはループに供給され、while read
リストに従ってファイル名を変更し、古いファイルを上書きしないようにサフィックスを追加します。 2番目のループはサフィックスを削除します。
上記は、ファイル名にタブや改行文字が含まれていないと仮定しています。
(実現できます。シャッフリングアルゴリズムシェルで手動で実行しますが、少し混乱しているようです。 )
答え2
説明する
これは問題を解決する最短の方法ではありませんが、理解しやすいと思います。
生ファイルでタールボールを作成することをお勧めします
tar -cvzf backup.tar.gz file*
テスト(または繰り返しテスト)後に復元する機能
tar -xvf backup.tar.gz
- 一時ファイルを使用しました
- コピーコマンドを使用してファイルをビルドするには、
- ファイル名を混ぜてください
"$tmpdir"/tg3
。 - これらのコマンドを実行すると、元のファイルはまだ存在します。
- 最後に、彼らは覆われています。
- プロセスが完了し、一時ディレクトリを削除できます。
シェルスクリプトshuffler
#!/bin/bash
tmpdir=$(mktemp -d)
curdir=$(pwd)
ls -1 file* > "$tmpdir"/orig # list the file names in a file
sed -i -e 's/^/"/' -e 's/$/"/' "$tmpdir"/orig # quote to allow special chars
cd "$tmpdir"
shuf orig > shuf # shuffle the names
paste orig shuf > tg1 # build commands ...
sed 's/^/cp /' tg1 > tg2 # build commands
sed 's/"$/xtmp"/' tg2 > tg3 # make temporary names
#less tg3
cd "$curdir"
bash "$tmpdir"/tg3 # copy the files to shuffled temporary names
rename -f 's/xtmp$//' file* # overwrite the original files
rm -r "$tmpdir"
デモの例
ディレクトリの作成/選択
内容がファイル名と一致するテストファイルを作成します。
for ((i=1;i<100;i++));do echo $i>file_$i;done
ファイルをタールボールに保存
tar -cvzf backup.tar.gz file*
ここからシェルスクリプトをテキストエディタにコピーし、
shuffler
その名前で同じディレクトリに保存します。シェルスクリプトを実行可能にする
chmod +x shuffler
太陽
./shuffler
次のコマンドラインを使用して、ファイルが実際にスクランブルされていることを確認できます(この特定のテスト例でのみ機能します)。
$ for ((i=1;i<100;i++));do echo -n "file_$i: ";j=$(cat file_$i);if [ "$i" == "$j" ]; then echo "$j same";else echo "$j";fi;done
file_1: 98
file_2: 45
file_3: 1
file_4: 5
file_5: 93
file_6: 31
file_7: 52
file_8: 84
file_9: 57
file_10: 44
file_11: 2
file_12: 92
file_13: 32
file_14: 12
file_15: 38
file_16: 10
file_17: 64
file_18: 75
file_19: 30
file_20: 68
file_21: 87
file_22: 26
file_23: 36
file_24: 53
file_25: 50
file_26: 51
file_27: 41
file_28: 49
file_29: 21
file_30: 17
file_31: 61
file_32: 73
file_33: 9
file_34: 16
file_35: 55
file_36: 85
file_37: 24
file_38: 83
file_39: 59
file_40: 18
file_41: 20
file_42: 29
file_43: 66
file_44: 82
file_45: 56
file_46: 48
file_47: 71
file_48: 79
file_49: 14
file_50: 86
file_51: 60
file_52: 43
file_53: 22
file_54: 54 same
file_55: 19
file_56: 89
file_57: 28
file_58: 34
file_59: 77
file_60: 88
file_61: 58
file_62: 4
file_63: 96
file_64: 94
file_65: 39
file_66: 69
file_67: 65
file_68: 7
file_69: 90
file_70: 6
file_71: 8
file_72: 47
file_73: 80
file_74: 25
file_75: 97
file_76: 33
file_77: 13
file_78: 15
file_79: 81
file_80: 37
file_81: 42
file_82: 78
file_83: 74
file_84: 3
file_85: 95
file_86: 76
file_87: 40
file_88: 70
file_89: 99
file_90: 27
file_91: 23
file_92: 11
file_93: 91
file_94: 62
file_95: 35
file_96: 63
file_97: 46
file_98: 72
file_99: 67
下にスクロールしてfile_54
同じであることを確認してください。他のすべてのファイルには新しい内容があります。カードスーツのように2〜3回混ぜることができます。
tarballでファイル名をリセットしてやり直すこともでき、shuf
新しい開始値が得られるので、毎回新しい結果が得られます。
答え3
シンボリックリンクのアイデアに従ってCtrl-Alt-Delor、GNU coreutilsを使用するshuf
(このコードはまた、readlink -f
GNU coreutilsを使用して指定されたファイルの絶対パス名を取得し、シンボリックリンクを生成します):
#!/bin/sh -e
shufdir=shufdir # directory at this path will be deleted and recreated
rm -rf "$shufdir"
mkdir -p "$shufdir"
printf '%s\n' "$@" | shuf |
while read -r fname; do
ln -s "$( readlink -f "$1" )" "$shufdir/$fname"
shift
done
このスクリプトはファイル名を取得し、コマンドラインから混合します。サブディレクトリを作成し$shufdir
、指定されたすべてのファイル名を混在させます。その後、混在したファイル名は、$shufdir
コマンドラインで指定された元のファイル名のリストにシンボリックリンクされます。
このコードは、パス名に改行文字が含まれていないと仮定します。
テスト:
$ ls -l
total 4
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-1
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-10
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-2
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-3
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-4
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-5
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-6
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-7
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-8
-rw-r--r-- 1 kk wheel 0 Mar 14 18:13 file-9
-rw-r--r-- 1 kk wheel 247 Mar 14 18:39 script.sh
$ sh script.sh file-*
$ ls -l shufdir/
total 0
lrwxr-xr-x 1 kk wheel 31 Mar 14 18:39 file-1 -> /tmp/shell-yash.WkdNi1GD/file-8
lrwxr-xr-x 1 kk wheel 31 Mar 14 18:39 file-10 -> /tmp/shell-yash.WkdNi1GD/file-9
lrwxr-xr-x 1 kk wheel 31 Mar 14 18:39 file-2 -> /tmp/shell-yash.WkdNi1GD/file-4
lrwxr-xr-x 1 kk wheel 31 Mar 14 18:39 file-3 -> /tmp/shell-yash.WkdNi1GD/file-1
lrwxr-xr-x 1 kk wheel 31 Mar 14 18:39 file-4 -> /tmp/shell-yash.WkdNi1GD/file-3
lrwxr-xr-x 1 kk wheel 31 Mar 14 18:39 file-5 -> /tmp/shell-yash.WkdNi1GD/file-2
lrwxr-xr-x 1 kk wheel 31 Mar 14 18:39 file-6 -> /tmp/shell-yash.WkdNi1GD/file-6
lrwxr-xr-x 1 kk wheel 31 Mar 14 18:39 file-7 -> /tmp/shell-yash.WkdNi1GD/file-7
lrwxr-xr-x 1 kk wheel 31 Mar 14 18:39 file-8 -> /tmp/shell-yash.WkdNi1GD/file-5
lrwxr-xr-x 1 kk wheel 32 Mar 14 18:39 file-9 -> /tmp/shell-yash.WkdNi1GD/file-10
何もあなたを止めることはできませんコピーまたは移動するファイルを新しいディレクトリにコピーするか、次を使用します。ハードリンクシンボリックリンクの代わりに($shufdir
ディレクトリがソースファイルと同じパーティションにある場合)、コマンドを使用して行を変更できますln -s
。
答え4
Fisher-Yates シャッフリングアルゴリズムを使用するスクリプトは次のとおりです。
#!/bin/bash
function swapnames() {
if [ ! "$2" == "$1" ]; then
tf=$(mktemp "$1.XXXXXX") && mv "$1" "$tf" && mv "$2" "$1" && mv "$tf" "$2"
fi
}
function shufflenames() {
workdir=$1
pattern=$2
if [ "$workdir" == "" ]; then workdir="."; fi
if [ "$pattern" == "" ]; then pattern="*"; fi
fs=$(printf "%s\n" "$workdir"/$pattern)
IFS=$'\n' fs=($fs)
fslen=${#fs[@]}
ind=1
while [ $ind -lt $fslen ]; do
ran=$(($RANDOM%($ind+1)))
echo swapnames "${fs[$ran]}" "${fs[$ind]}"
swapnames "${fs[$ran]}" "${fs[$ind]}"
code=$?
if [ ! $code -eq 0 ]; then return $code; fi
ind=$(($ind+1))
done
}
shufflenames $1 $2
その後、次のことができます。
./shufflenames picsdir
または
./shufflenames picsdir *.png