디렉토리에서 파일 이름을 무작위로 섞는 방법

디렉토리에서 파일 이름을 무작위로 섞는 방법

파일 이름 디렉터리가 있다고 가정해 보겠습니다.

  • File_010.ext
  • File_011.ext
  • ...
  • File_99.ext

각 파일을 가져와서 중복 없이 디렉터리의 다른 이름으로 무작위로 이름을 바꾸어 검사할 때 디렉터리는 동일해 보이지만 내용은 재배열되도록 하는 가장 간단한 방법은 무엇입니까?

답변1

이것은 shufGNU 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한 열에는 순서가 지정된 파일 이름 목록이 있고 다른 열에는 섞인 파일 이름 목록이 있도록 두 목록을 결합합니다. (사용하지 않으려면 임시 파일에 목록을 작성할 수 있습니다.프로세스 교체위와 같이 또는 쉘이 이를 지원하지 않는 경우 IFS=$'\t'. )IFS=$(printf '\t')$''

그런 다음 이것은 루프에 공급되고 while read목록에 따라 파일 이름을 바꾸고 이전 파일을 덮어쓰지 않도록 접미사를 추가합니다. 두 번째 루프는 접미사를 제거합니다.

위의 내용은 파일 이름에 탭이나 개행 문자가 포함되어 있지 않다고 가정합니다.

(구현할 수 있습니다.셔플링 알고리즘쉘에서 수동으로 수행하지만 약간 혼란스러운 것 같습니다. )

답변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동일한지 확인하세요. 다른 모든 파일에는 새로운 내용이 있습니다. 카드 한 벌처럼 두세 번 섞을 수 있습니다.

tarball에서 파일 이름을 재설정하고 다시 수행할 수도 있으며, shuf새로운 시작 값을 얻게 되므로 매번 새로운 결과를 얻게 됩니다.

답변3

심볼릭 링크 아이디어를 따르면서Ctrl-Alt-Delor, GNU coreutils 사용 shuf(이 코드는 또한 readlink -fGNU 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

관련 정보