이 주제에 대해 허용되는 답변에서 영감을 얻었습니다.디렉토리에 있는 임의의 파일 X개 나열, 현재 디렉터리의 각 하위 폴더에서 파일을 선택하기 위해 두 줄을 합치려고 시도했지만 성공하지 못했습니다.
rand() REPLY=$RANDOM
for x in *; do y=$($x/*(o+rand[1])); print ${y:r}; done
y
확장 프로그램이 제대로 작동하지 않는 것 같습니다 . 왜?
위 코드에 어떤 문제가 있나요?
답변1
문제는 의 확장이 아니라 y
그것에 할당된 값이다.y
당신은 이것을 가지고 있습니다
y=$($x/*(o+rand[1]))
할당된 값은 명령 대체( )의 결과입니다 $(…)
. 대체 명령의 유일한 "단어"는 glob 표현식입니다. 이는 선택한 파일을 명령으로 실행하려고 시도한다는 의미입니다(이로 인해 오류가 발생하고 유용한 출력이 생성되지 않을 수 있음).
작동하게 하려면(변경된 의미에도 불구하고) 명령 대체 할당을 배열 할당으로 변경할 수 있습니다(예: 다음 제거 $
) =
.
y=($x/*(o+rand[1]))
명령 대체를 유지하려면 명령으로 실행하는 대신 선택한 경로 이름을 출력하도록 해야 합니다.
y=$(print -- $x/*(o+rand[1]))
하지만 여기에는 숨겨진 문제가 있습니다. 각 glob은 별도의 하위 쉘에서 평가되므로 각 디렉터리는 동일한 난수 시퀀스를 사용하여 항목을 정렬합니다. 각 디렉터리에 대해 REPLY에 할당된 값의 순서를 사용 하고 살펴보면 set -x
이를 관찰할 수 있습니다 . 이는 파일이 디렉터리 전체에서 독립적으로 선택되지 않음을 의미합니다.
다음은 매개변수에 전역 확장을 할당하는 데 사용할 수 있는 몇 가지 대안입니다(이러한 계산은 $RANDOM
동일한 셸에서 유지되므로 선택이 (더) 독립적이 됩니다):
for y in $x/*(o+rand[1]); do print -- ${y:r}; done
set -- $x/*(o+rand[1]); print -l -- ${@:r}
빈 디렉토리를 처리하려면 아마도 N
glob 한정자를 추가해야 할 것입니다(NULL_GLOB 설정과 마찬가지로). 이는 외부 glob과 일치하는 디렉터리가 아닌 경우에도 도움이 됩니다( /
glob 한정자를 사용하여 디렉터리로만 제한할 수는 있지만).
rand() REPLY=$RANDOM
for x in *(/); do y=($x/*(No+rand[1])); print -l -- ${y:r}; done
답변2
와일드카드에 수정자를 추가할 수 있습니다.
for x (*(/)) print -rl -- $x/*(No+rand[1]:r)
또한보십시오:
print -rl -- *(N/e{'REPLY=($REPLY/*(No+rand[1]:r))'})