다음을 포함하는 인수로 전달된 디렉터리 집합에서 파일을 선택하려고 합니다.
${@/%/*}
그러나 이는 공백이 있는 경로가 손상되고 인용 매개변수 확장으로 인해 파일 이름 확장이 중지되므로 이상적이지 않습니다. 만족스러운 해결책이 있나요?
추신: 이 작업을 수행해야 한다는 것을 알고 있지만 find -maxdepth
매개변수 확장과 와일드카드를 혼합하는 것이 왜 그렇게 어려운지 궁금합니다.
답변1
언제든지 다음과 같이 할 수 있습니다.
IFS= # don't split
files=(${@/%/*}) # use split+glob upon expansion with split disabled
그러나 "$@"
와일드카드 문자가 포함된 경우 와일드카드 문자로 해석됩니다. 또한 일치하지 않는 모든 glob에 대해 확장되지 않은 패턴이 생성됩니다.
nullglob
루프와 옵션을 사용하여 다음 문제를 해결할 수 있습니다.
shopt -s nullglob
files=()
for arg do files+=("$arg"*); done
zsh
또는 대신 다음을 사용할 수 있습니다 bash
.
files=($^argv*(N))
$^array
rcexpandparam
확장 옵션을 엽니다 $array
. rc
셸(및 셸에서도 fish
) 에서 $array*
where는 $array
두 요소를 가져와 a
로 b
확장하므로 a*
여기서는 b*
do와 같습니다 files=($argv[1]*(N) $argv[2]*(N)...)
( $argv[1]
do와 동일 $1
, 좀 더 장황함). 이는 그 자체로 glob의 동작을 (N)
켜는 glob 한정자입니다 .nullglob
fish
셸 에서는 다음과 같습니다.
set files $argv*
as는 인수에서 유사한 동작을 fish
활성화 하고 유사하게 배열을 확장합니다 . 하지만 more than과 구문이 완전히 다르다는 점에 유의하세요.nullglob
set
rc
fish
bash
zsh
이는 원하는 대로 "$1"*
전 세계적으로 확장되도록 설계되었습니다. 만약 당신이 실제로... 방울을 의미한다면, 당신의"$2"*
${@/%/*}
"$1"/*
"%2"/*
인수로 전달된 디렉터리의 파일 집합제안사항은 위의 코드 조각에서 ${@/%/\/*}
, , 를 "$arg"/*
사용해야 한다는 것입니다 $^argv/*(N)
.$argv*
답변2
다른 와일드카드 문자를 백슬래시+문자로 바꿉니다. 공백 문자를 백슬래시+ 문자로 바꾸거나 (보다 강력하게) IFS
빈 문자열로 설정합니다. 이전 이스케이프 단계에서 생성된 백슬래시를 다시 이스케이프하지 않도록 먼저 백슬래시를 이스케이프해야 합니다. 그러나 이스케이프할 것이 없으면 아무 것도 이스케이프하지 마십시오. 백슬래시는 와일드카드가 있는 경우에만 특별하기 때문입니다.
nullglob
일치하는 항목이 없는 경우 확장되지 않은 패턴 대신 빈 목록을 가져오려면 이 옵션을 설정하세요. 함수에서 이 작업을 수행하고 변경 사항이 셸 옵션과 로컬에 유지되도록 준비합니다 IFS
.
최소한의 테스트:
function set_patterns {
typeset restore_shopt=$(shopt -p nullglob)
shopt -s nullglob
typeset IFS=
typeset x
patterns=()
for x; do
if [[ "$x" == *[*?[]* ]]; then
x="${x//\\/\\\\}"
x="${x//\*/\\*}"
x="${x//\?/\\?}"
x="${x//\[/\\[}"
fi
x="${x//%/*}"
patterns+=($x)
done
eval "$restore_shopt"
}