bash의 디렉토리에서 임의 파일을 선택하려면 어떻게 해야 합니까?
저는 약 2000개의 파일이 있는 디렉토리를 가지고 있습니다.의 랜덤 샘플을 선택하려면 어떻게 해야 합니까?N
명령 합니다. ? 스 립 또 piped 명 록 사 하 여 파 일 처 합 니 리 까 을 용령 bash을목 는크트 ?까니▁files합리처?
GNU 정렬의 임의 옵션을 사용하는 스크립트는 다음과 같습니다.
ls |sort -R |tail -$N |while read file; do
# Something involving $file, or you can leave
# off the while to just get the filenames
done
사용할 수 있습니다.shuf
(GNU coreutils 패키지에서) 그것을 위해.에서 첫 줄을 : 파일이름목록입임고순의첫서열줄됩반요록니다청면하도환하을번째.
ls dirname | shuf -n 1
# probably faster and more flexible:
find dirname -type f | shuf -n 1
# etc..
을 합니다.-n, --head-count=COUNT
원하는 줄의 수를 반환하는 값입니다.예를 들어, 5개의 임의 파일 이름을 반환하려면 다음을 사용합니다.
find dirname -type f | shuf -n 5
다음은 출력을 구문 분석하지 않는 몇 가지 가능성입니다.ls
이름에 공백과 재미있는 기호가 있는 파일에 대해서는 100% 안전합니다. 모두는 입니다.randf
임의 파일 목록과 함께.이 어레이는 다음으로 쉽게 인쇄할 수 있습니다.printf '%s\n' "${randf[@]}"
필요한 경우에는
은 아마도 번 이고, 이파일동여러을번수있출으며할력일파일한은,
N
미리 알려야 합니다.여기서 저는 N=42를 선택했습니다.a=( * ) randf=( "${a[RANDOM%${#a[@]}]"{1..42}"}" )
이 기능은 잘 문서화되어 있지 않습니다.
만약 , 의 가능성을 , 여러분은 만이 N않만미지았지지, 가면정있이다다수니, 신사할습용당했은좋아를 사용할 수 .
eval
하지만 그건 사악해요 그리고 당신은 정말로 확실하게 해야해요N
철저한 확인 없이 사용자 입력에서 직접 나오지 않습니다!N=42 a=( * ) eval randf=( \"\${a[RANDOM%\${#a[@]}]\"\{1..$N\}\"}\" )
저는 개인적으로 싫어합니다.
eval
그러므로 이 대답은!보다 간단한 방법(루프)을 사용하는 경우에도 마찬가지입니다.
N=42 a=( * ) randf=() for((i=0;i<N;++i)); do randf+=( "${a[RANDOM%${#a[@]}]}" ) done
동일한 파일을 여러 번 사용하지 않으려는 경우:
N=42 a=( * ) randf=() for((i=0;i<N && ${#a[@]};++i)); do ((j=RANDOM%${#a[@]})) randf+=( "${a[j]}" ) a=( "${a[@]:0:j}" "${a[@]:j+1}" ) done
참고. 이전 게시물에 대한 늦은 답변입니다. 그러나 승인된 답변은 끔찍한 bash 관행을 보여주는 외부 페이지로 연결되며, 다른 답변은 또한 의 출력을 구문 분석하기 때문에 그다지 좋지 않습니다.ls
수락된 답변에 대한 코멘트는 분명히 좋은 관행을 보여주지만 OP에 정확하게 답변하지 않는 Lunath의 훌륭한 답변을 가리킵니다.
ls | shuf -n 10 # ten random files
▁을 선택하는 간단한 5
ls 구문 분석을 피하는 동안 임의 파일.또한 공백, 줄 바꿈 및 기타 특수 문자가 포함된 파일에서도 작동합니다.
shuf -ezn 5 * | xargs -0 -n1 echo
를 바꿉니다.echo
파일에 대해 실행할 명령을 사용합니다.
투표한 @답변에 대한 더 입니다. 답변이기 (한은 회피를 @gniourf_gniourf_gniourf를 피했습니다.) 제가 방금 투표한 것은 그것이 단연 최고의 답변이기 때문입니다. 두 번 더. (한 번 피해서)eval
안전한 파일 이름 처리를 위해 한 번만 사용할 수 있습니다.)
하지만 이 답변에서 사용하는 "문서화되지 않은" 기능을 푸는 데 몇 분이 걸렸습니다.Bash 스킬이 어떻게 작동하는지 즉시 확인할 수 있을 정도로 견고하다면 이 설명을 건너뜁니다.하지만 저는 그러지 않았고, 그것을 풀었으니 설명할 가치가 있다고 생각합니다.
기능 #1은 셸 자체의 파일 글로빙입니다. a=(*)
배을작니다를 .$a
현재 디렉토리에 있는 파일의 구성원.Bash는 파일 이름의 모든 이상한 점을 이해하므로 목록이 정확하고 탈출이 보장됩니다.반환된 텍스트 파일 이름을 제대로 구문 분석할 필요가 없습니다.ls
.
기능 #2는 배열에 대한 Bash 매개 변수 확장으로, 하나는 다른 하나에 중첩됩니다.시작은${#ARRAY[@]}
의 길이로 확장됩니다.$ARRAY
.
그런 다음 해당 확장을 사용하여 배열을 첨자합니다.1과 N 사이의 난수를 찾는 표준 방법은 난수 모듈 N의 값을 구하는 것입니다.우리는 배열의 길이와 0 사이의 난수를 원합니다.명확성을 위해 두 줄로 나뉜 접근 방식은 다음과 같습니다.
LENGTH=${#ARRAY[@]}
RANDOM=${a[RANDOM%$LENGTH]}
그러나 이 솔루션은 이를 한 줄로 수행하여 불필요한 변수 할당을 제거합니다.
특징 #3은 Bash brace 확장이지만 완전히 이해하지는 못합니다.예를 들어, 브레이스 확장은 이름이 지정된 25개의 파일 목록을 생성하는 데 사용됩니다.filename1.txt
,filename2.txt
기타::echo "filename"{1..25}".txt"
.
에 있는 인 위의서셸안있표는현은식에브▁the▁above식,은,"${a[RANDOM%${#a[@]}]"{1..42}"}"
그 속임수를 사용하여 42개의 분리된 확장을 만듭니다.브레이스 확장은 한 자리 숫자를 그 사이에 배치합니다.]
리고그고.}
처음에는 배열을 구독하는 줄 알았지만, 그렇다면 콜론이 선행될 것입니다. (또한 배열의 임의의 위치에서 42개의 항목을 연속적으로 반환했을 것이며, 이는 배열에서 42개의 임의의 항목을 반환하는 것과 전혀 동일하지 않습니다.)저는 단지 셸이 확장을 42번 실행하도록 만들어서 어레이에서 42개의 랜덤 항목을 반환하는 것이라고 생각합니다. (하지만 누군가가 좀 더 자세히 설명해 준다면, 저는 그것을 듣고 싶습니다.)
N을 42로 하드 코딩해야 하는 이유는 변수 확장 전에 가새 확장이 발생하기 때문입니다.
마지막으로 디렉토리 계층에 대해 재귀적으로 이 작업을 수행하려면 다음 기능 #4를 참조하십시오.
shopt -s globstar
a=( ** )
이것은 다음과 같은 원인이 되는 셸 옵션을 켭니다.**
재귀적으로 일치시킵니다.이제 당신의$a
배열에는 전체 계층의 모든 파일이 포함됩니다.
Python을 설치한 경우(Python 2 또는 Python 3과 함께 작동):
하나의 파일(또는 임의 명령에서 줄)을 선택하려면 다음을 사용합니다.
ls -1 | python -c "import sys; import random; print(random.choice(sys.stdin.readlines()).rstrip())"
택하기선을 N
: "/", ""(으)")N
하십시오. 이 명령은 다음과 같습니다. 이 명령어는 다음과 같습니다.
ls -1 | python -c "import sys; import random; print(''.join(random.sample(sys.stdin.readlines(), int(sys.argv[1]))).rstrip())" N
이러한 파일의 샘플을 다른 폴더에 복사하려면 다음을 수행합니다.
ls | shuf -n 100 | xargs -I % cp % ../samples/
샘플 디렉토리를 먼저 만듭니다.
MacOS에는 sort -R 및 shuf 명령어가 없기 때문에 중복 없이 모든 파일을 랜덤화하는 bash 전용 솔루션이 필요했지만 여기서는 찾을 수 없었습니다.이 솔루션은 gniourf_gniourf의 솔루션 #4와 유사하지만 더 나은 설명을 추가할 수 있기를 바랍니다.
if 또는 $RANDOM의 루프에 대한 gniourf_gniourf는 ~32000개의 파일로 제한되지만 대부분의 경우 스크립트는 if 또는 gniourf가 포함된 카운터를 사용하여 N개의 샘플을 중지하도록 수정하기가 쉬워야 합니다.
#!/bin/bash
array=(*) # this is the array of files to shuffle
# echo ${array[@]}
for dummy in "${array[@]}"; do # do loop length(array) times; once for each file
length=${#array[@]}
randomi=$(( $RANDOM % $length )) # select a random index
filename=${array[$randomi]}
echo "Processing: '$filename'" # do something with the file
unset -v "array[$randomi]" # set the element at index $randomi to NULL
array=("${array[@]}") # remove NULL elements introduced by unset; copy array
done
폴더에 더 많은 파일이 있으면 unix stack exchange에서 찾은 아래의 piped 명령을 사용할 수 있습니다.
find /some/dir/ -type f -print0 | xargs -0 shuf -e -n 8 -z | xargs -0 cp -vt /target/dir/
, 다른.cp
.
이것이 MacOS에서 bash와 함께 좋은 플레이를 할 수 있는 유일한 스크립트입니다.저는 다음 두 링크의 스니펫을 결합하고 편집했습니다.
ls 명령: 파일당 한 줄씩 재귀적인 전체 경로 목록을 얻으려면 어떻게 해야 합니까?
#!/bin/bash
# Reads a given directory and picks a random file.
# The directory you want to use. You could use "$1" instead if you
# wanted to parametrize it.
DIR="/path/to/"
# DIR="$1"
# Internal Field Separator set to newline, so file names with
# spaces do not break our script.
IFS='
'
if [[ -d "${DIR}" ]]
then
# Runs ls on the given dir, and dumps the output into a matrix,
# it uses the new lines character as a field delimiter, as explained above.
# file_matrix=($(ls -LR "${DIR}"))
file_matrix=($(ls -R $DIR | awk '; /:$/&&f{s=$0;f=0}; /:$/&&!f{sub(/:$/,"");s=$0;f=1;next}; NF&&f{ print s"/"$0 }'))
num_files=${#file_matrix[*]}
# This is the command you want to run on a random file.
# Change "ls -l" by anything you want, it's just an example.
ls -l "${file_matrix[$((RANDOM%num_files))]}"
fi
exit 0
저는 이것을 사용합니다. 이것은 임시 파일을 사용하지만 일반 파일을 찾아서 반환할 때까지 디렉터리에 깊이 들어갑니다.
# find for a quasi-random file in a directory tree:
# directory to start search from:
ROOT="/";
tmp=/tmp/mytempfile
TARGET="$ROOT"
FILE="";
n=
r=
while [ -e "$TARGET" ]; do
TARGET="$(readlink -f "${TARGET}/$FILE")" ;
if [ -d "$TARGET" ]; then
ls -1 "$TARGET" 2> /dev/null > $tmp || break;
n=$(cat $tmp | wc -l);
if [ $n != 0 ]; then
FILE=$(shuf -n 1 $tmp)
# or if you dont have/want to use shuf:
# r=$(($RANDOM % $n)) ;
# FILE=$(tail -n +$(( $r + 1 )) $tmp | head -n 1);
fi ;
else
if [ -f "$TARGET" ] ; then
rm -f $tmp
echo $TARGET
break;
else
# is not a regular file, restart:
TARGET="$ROOT"
FILE=""
fi
fi
done;
여기 강 선생님이 약간 개발한 펄 솔루션은 어떻습니까?
유닉스 명령줄 또는 셸 스크립트에서 텍스트 파일의 줄을 섞으려면 어떻게 해야 합니까?
ls | perl -MLIST::Util=sshuff -e '@lines = shuffle(<>); print @lines[0..4]'
언급URL : https://stackoverflow.com/questions/414164/how-can-i-select-random-files-from-a-directory-in-bash
'programing' 카테고리의 다른 글
HTML을 사용하여 문서의 모든 인쇄 페이지에서 머리글과 바닥글을 인쇄하는 방법은 무엇입니까? (0) | 2023.06.04 |
---|---|
안드로이드 애플리케이션에서 이메일을 보내는 방법은 무엇입니까? (0) | 2023.06.04 |
Android용 Gradle을 사용하여 외장형 aar 패키지를 수동으로 포함하는 방법 (0) | 2023.06.04 |
Xcode 디버깅 - 이미지 표시 (0) | 2023.06.04 |
Aurora 페일오버로 인해 연결이 읽기 전용 상태로 유지됨 (0) | 2023.06.04 |