약 2000 개의 파일이있는 디렉토리가 있습니다. N
bash 스크립트 또는 파이프 명령 목록을 사용하여 임의의 파일 샘플을 선택하려면 어떻게 해야합니까?
답변
다음은 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
참고 . 이전 게시물에 대한 답변은 늦었지만 허용 된 답변은 외부 페이지로 연결되며세게 때리다연습하고 다른 답변은의 출력을 구문 분석하기 때문에 훨씬 좋지 않습니다 ls
. 허용 된 답변에 대한 의견은 Lhunath의 훌륭한 답변을 나타내며, 이는 우수 사례를 분명히 보여 주지만 OP에 정확히 답변하지는 않습니다.
답변
ls | shuf -n 10 # ten random files
답변
ls 구문 분석5
을 피하면서 임의의 파일 을 선택하는 간단한 솔루션입니다 . 또한 공백, 개행 및 기타 특수 문자가 포함 된 파일과 함께 작동합니다.
shuf -ezn 5 * | xargs -0 -n1 echo
대체 echo
당신이 당신의 파일을 실행하려는 명령.
답변
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
답변
이것은 @gniourf_gniourf의 늦은 답변에 대한 심지어 나중에 답변입니다. eval
안전한 파일 이름 처리 를 피하기 위해 한 번.
그러나이 답변에서 사용하는 “잘 문서화되지 않은”기능을 풀려면 몇 분이 걸렸습니다. Bash 기술이 충분히 작동하여 즉시 작동 방식을 확인한 경우이 설명을 건너 뛰십시오. 그러나 나는 그것을 풀지 않았고 그것을 풀었을 때 나는 그것이 가치가 있다고 생각합니다.
기능 # 1 은 쉘 자체의 파일 글 로빙입니다. 멤버가 현재 디렉토리의 파일 인 a=(*)
배열을 만듭니다 $a
. Bash는 파일 이름의 모든 기묘함을 이해하므로 목록이 정확하고 이스케이프 등을 보장합니다 ls
.에서 반환 된 텍스트 파일 이름을 올바르게 구문 분석 할 필요가 없습니다 .
기능 # 2 는 배열 에 대한 Bash 매개 변수 확장 입니다 . 이것은로 시작 하여 길이로 확장됩니다 .${#ARRAY[@]}
$ARRAY
그런 다음 해당 확장을 사용하여 배열을 첨자 화합니다. 1과 N 사이의 난수를 찾는 표준 방법은 난수 modulo N의 값을 취하는 것입니다. 우리는 0과 배열의 길이 사이의 난수를 원합니다. 명확성을 위해 두 줄로 나눈 접근 방식은 다음과 같습니다.
LENGTH=${#ARRAY[@]}
RANDOM=${a[RANDOM%$LENGTH]}
그러나이 솔루션은 한 줄로 수행하여 불필요한 변수 할당을 제거합니다.
Feature # 3 은 Bash brace expansion 이지만, 완전히 이해하지는 못하지만 고백해야합니다. 중괄호 확장라는 25 개 파일 목록 생성하기 위해, 예를 들어, 사용 filename1.txt
, filename2.txt
등, : echo "filename"{1..25}".txt"
.
위의 서브 쉘 내부의 표현식 "${a[RANDOM%${#a[@]}]"{1..42}"}"
은 해당 트릭을 사용하여 42 개의 개별 확장을 생성합니다. 브레이스 팽창 사이의 한 자리에 배치 ]
하고, }
제 I의 생각에 배열 첨자하고,하지만, 그렇다면 그것은 콜론이 선행되어야한다. (또한 배열의 임의의 지점에서 42 개의 연속 항목을 반환했을 것입니다. 이는 배열에서 임의의 42 개의 항목을 반환하는 것과 전혀 다릅니다.) 쉘이 확장을 42 번 실행하여 반환하는 것으로 생각합니다. 배열에서 42 개의 랜덤 아이템. (그러나 누군가가 더 자세히 설명 할 수 있다면 듣고 싶습니다.)
N이 42까지 하드 코딩되어야하는 이유는 변수 확장 전에 가새 확장이 발생하기 때문입니다.
마지막으로 디렉토리 계층 구조에 대해이 작업을 반복적으로 수행하려면 기능 # 4 가 있습니다.
shopt -s globstar
a=( ** )
A의이 회전 쉘 옵션 의 원인 **
재귀 적으로 일치합니다. 이제 $a
배열에는 전체 계층 구조의 모든 파일이 포함됩니다.