[bash] bash의 디렉토리에서 임의의 파일을 어떻게 선택합니까?

약 2000 개의 파일이있는 디렉토리가 있습니다. Nbash 스크립트 또는 파이프 명령 목록을 사용하여 임의의 파일 샘플을 선택하려면 어떻게 해야합니까?



답변

다음은 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 # 3Bash 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배열에는 전체 계층 구조의 모든 파일이 포함됩니다.