이 답변에는 모든 유형의 파일에 대한 솔루션 이 있습니다. 줄 바꿈 또는 공백으로.
최근 배쉬뿐만 아니라 고대 배쉬 및 오래된 posix 포탄에 대한 솔루션이 있습니다.
이 답변 [1] 에서 아래에 나열된 트리 가 테스트에 사용됩니다.
고르다
select
배열 로 쉽게 작업 할 수 있습니다 .
$ dir='deep/inside/a/dir'
$ arr=( "$dir"/* )
$ select var in "${arr[@]}"; do echo "$var"; break; done
또는 위치 매개 변수를 사용하여 :
$ set -- "$dir"/*
$ select var; do echo "$var"; break; done
따라서 유일한 실제 문제는 배열 내부 또는 위치 매개 변수 내부에 "파일 목록"(정확하게 구분 된)을 얻는 것입니다. 계속 읽으세요.
세게 때리다
bash 로보 고 한 문제가 보이지 않습니다. Bash는 주어진 디렉토리 안에서 검색 할 수 있습니다 :
$ dir='deep/inside/a/dir'
$ printf '<%s>\n' "$dir"/*
<deep/inside/a/dir/directory>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
또는 루프가 마음에 들면
$ set -- "$dir"/*
$ for f; do printf '<%s>\n' "$f"; done
<deep/inside/a/dir/directory>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
위의 구문은 (합리적) 셸 (적어도 csh는 아님)에서 올바르게 작동합니다.
위 구문의 유일한 한계는 다른 디렉토리로 내려가는 것입니다.
그러나 bash는 그렇게 할 수 있습니다.
$ shopt -s globstar
$ set -- "$dir"/**/*
$ for f; do printf '<%s>\n' "$f"; done
<deep/inside/a/dir/directory>
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/directory/file name>
<deep/inside/a/dir/directory/file with a
newline>
<deep/inside/a/dir/directory/zz last file>
<deep/inside/a/dir/file>
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/zz last file>
파일로 끝나는 파일 과 같은 일부 파일 만 선택하려면 *를 바꾸십시오.
$ set -- "$dir"/**/*file
$ printf '<%s>\n' "$@"
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/directory/zz last file>
<deep/inside/a/dir/file>
<deep/inside/a/dir/zz last file>
건장한
제목에 "공간 안전 " 을 배치 하면 의미가 " 강력한 " 것으로 가정합니다 .
공백 (또는 개행)을 견고하게하는 가장 간단한 방법은 공백 (또는 개행)이있는 입력 처리를 거부하는 것입니다. 쉘에서이를 수행하는 매우 간단한 방법은 파일 이름이 공백으로 확장되면 오류로 종료하는 것입니다. 이를 수행하는 방법은 여러 가지가 있지만 가장 컴팩트 한 (및 posix) (서드 디렉토리 이름 및 도트 파일 방지를 포함하여 하나의 디렉토리 내용으로 제한됨)은 다음과 같습니다.
$ set -- "$dir"/file* # read the directory
$ a="$(printf '%s' "$@" x)" # make it a long string
$ [ "$a" = "${a%% *}" ] || echo "exit on space" # if $a has an space.
$ nl='
' # define a new line in the usual posix way.
$ [ "$a" = "${a%%"$nl"*}" ] || echo "exit on newline" # if $a has a newline.
사용 된 솔루션이 해당 항목 중 하나라도 견고하면 테스트를 제거하십시오.
bash에서 하위 디렉토리는 위에서 설명한 **를 사용하여 한 번에 테스트 할 수 있습니다.
도트 파일을 포함하는 몇 가지 방법이 있습니다. Posix 솔루션은 다음과 같습니다.
set -- "$dir"/* "$dir"/.[!.]* "$dir"/..?*
찾기
어떤 이유로 찾기를 사용해야하는 경우 구분 기호를 NUL (0x00)로 바꾸십시오.
배쉬 4.4+
$ readarray -t -d '' arr < <(find "$dir" -type f -name file\* -print0)
$ printf '<%s>\n' "${arr[@]}"
<deep/inside/a/dir/file name>
<deep/inside/a/dir/file with a
newline>
<deep/inside/a/dir/directory/file name>
<deep/inside/a/dir/directory/file with a
newline>
<deep/inside/a/dir/directory/file>
<deep/inside/a/dir/file>
배쉬 2.05+
i=1 # lets start on 1 so it works also in zsh.
while IFS='' read -d '' val; do
arr[i++]="$val";
done < <(find "$dir" -type f -name \*file -print0)
printf '<%s>\n' "${arr[@]}"
POSIXLY
find에 NUL 구분 기호가없고 읽을 수있는 -d
(또는 -a
) 없는 유효한 POSIX 솔루션을 만들려면 완전히 다른 접근 방식이 필요합니다.
-exec
쉘을 호출하여 find 에서 컴플렉스를 사용해야합니다 .
find "$dir" -type f -exec sh -c '
for f do
echo "<$f>"
done
' sh {} +
또는 필요한 것이 select 인 경우 (select는 sh가 아닌 bash의 일부입니다) :
$ find "$dir" -type f -exec bash -c '
select f; do echo "<$f>"; break; done ' bash {} +
1) deep/inside/a/dir/file name
2) deep/inside/a/dir/zz last file
3) deep/inside/a/dir/file with a
newline
4) deep/inside/a/dir/directory/file name
5) deep/inside/a/dir/directory/zz last file
6) deep/inside/a/dir/directory/file with a
newline
7) deep/inside/a/dir/directory/file
8) deep/inside/a/dir/file
#? 3
<deep/inside/a/dir/file with a
newline>
[1] 이 트리 (\ 012는 개행) :
$ tree
.
└── deep
└── inside
└── a
└── dir
├── directory
│ ├── file
│ ├── file name
│ └── file with a \012newline
├── file
├── file name
├── otherfile
├── with a\012newline
└── zz last file
이 두 가지 명령으로 만들 수 있습니다.
$ mkdir -p deep/inside/a/dir/directory/
$ touch deep/inside/a/dir/{,directory/}{file{,\ {name,with\ a$'\n'newline}},zz\ last\ file}