Bash 스크립트를 작성 중인데 다음을 사용하여 배열을 만들어야 합니다.최신 이미지 파일 10개(최신 것부터 가장 오래된 것까지) 현재 디렉터리에 있습니다.
"이미지 파일"은 .jpg
또는 .png
. 일부 특정 이미지 유형만 지원하면 되며 이를 정규식(예: )으로 표현할 수도 있습니다 "\.(jpg|png)$"
.
내 질문은 예를 들어 이 작업을 수행하려고 하면 $list=(ls -1t *.jpg *.png | head -10)
각 파일 이름이 배열의 별도 요소가 되는 대신 결과 파일 목록이 어떻게든 하나의 요소가 된다는 것입니다.
.$list=(find -E . -iregex ".*(jpg|png)" -maxdepth 1 -type f | head -10)
또한 find 는 각 ./
파일 앞에 배치되는 것 같지만 sed
.find
$list
답변1
올바른 구문은 다음과 같습니다.
list=($(ls -t *.jpg *.png | head -10))
echo First element: ${list[0]}
echo Last element: ${list[9]}
그러나 이 해결 방법은 파일 이름에 공백 문자(또는 일반적으로 공백)가 포함된 경우 문제를 일으킵니다.
답변2
bash
≥ 4 의 경우 :
명령의 출력을 한 줄씩 배열로 읽으려면 다음을 사용해야 합니다 readarray
.
readarray files < <(ls -1t *.jpg *.png | head -10)
... 또는 mapfile
:
mapfile -t files < <(ls -1t *.jpg *.png | head -10)
그렇지 않으면:
files=()
while IFS= read -r f; do
files+=( "$f" )
done < <(ls -1t *.jpg *.png | head -10)
하지만, 파일 이름에 개행 문자가 허용되므로 파일 이름을 읽으려면 구분 기호 대신 구분 기호를 사용해야 find
합니다 .\0
ls -1
\n
files=()
while IFS= read -r -d $'\0' f; do
files+=("$f")
done < <(
find . -maxdepth 1 -type f \
-regextype posix-extended -iregex ".*\.(jpg|png)$" \
-printf '%T@\t%P\0' \
| sort -nrz \
| head -z -n 10 \
| cut -z -f2-
)
답변3
zsh가 옵션이라면 더 간단할 것입니다.
set -o nocaseglob
array=( *.(png|jpg)(Om[-10,-1]) )
또는 와 같이 대문자와 소문자를 set -o nocaseglob
더 쉽게 일치시킬 수 있는 png|jpg
변형입니다 .PNG
JpG
다음 명령문은 매우 구체적인 파일 이름 생성(glob)의 결과를 배열에 할당합니다. 왼쪽에서 오른쪽으로:
*.(png|jpg)
.jpg
.png
-- 활성화한 대소문자 구분 옵션에 따라 또는 로 끝나는 파일 이름 목록으로 확장됩니다.(Om ...)
O
-- 수정 시간(오래된 것부터 최신 것까지)에 따라 파일을 정렬하는 zsh "glob 한정자" (rder)[-10,-1]
-- 끝에 10개의 요소(가장 최근 파일 10개)를 가져오는 zsh 배열 연결
구문을 구문 분석할 수 있으면 zsh는 이와 같은 상황을 더 쉽게 처리할 수 있습니다. globbing/파일 이름 생성이 파일 이름을 처리하므로 구문 분석에 대해 걱정할 필요가 없습니다 ls
. 예를 들어, 내가 생성한 "재미있는" 파일 이름을 사용하면다른 답변, 결과는 다음과 같습니다.
$ print -l $array
4521.png
a?b.jpg
$( echo boom ).jpg
a*b.jpg
[x].jpg
X▒Y.jpg
single'quote.jpg
backslash.jpg
②.jpg
*.jpg
(일부 파일의 타임스탬프가 동일하기 때문에 정렬 결과가 약간 다릅니다.)
답변4
ls
외부 유틸리티와 bash v4+(연관 배열용)를 사용할 수 있는 경우 구문 분석 대신 stat
inode별로 파일 목록을 수집한 다음 최신 inode 목록을 수집하고 파일 이름 배열을 빌드할 수 있습니다.
shopt -s nocaseglob extglob
declare -a filesbyinode=()
for f in *.@(jpg|png); do filesbyinode[$(stat -c %i "$f")]=$f; done
[ ${#filesbyinode[@]} -gt 0 ] || return
declare wantedfiles=()
for inodes in $(stat -c '%Y %i' *.@(jpg|png) | sort -k1,1rn | awk '{print $2}' | head -10)
do
wantedfiles+=("${filesbyinode[$inodes]}")
done
declare -p wantedfiles
첫 번째 단계는 두 가지 셸 옵션을 설정하는 것입니다.
nocaseglob
-- 와일드카드jpg
일치가 가능합니다JPG
. (그리고JpG
...)extglob
-- 이는 다음을 허용합니다: 일치하는 파일 이름은@(jpg|png)
또는로 끝날 수 있습니다(위에 따라 다름).jpg
png
nocaseglob
그런 다음, inode로 파일 이름을 색인화하기 위해 빈 연관 배열을 설정합니다.
후속 루프는 for
inode 인덱스(명령 결과)와 파일 이름을 값으로 사용하여 배열을 구축합니다.filesbyinode
stat
파일이 없는 경우 return
상황(아마도 if/else)에 따라 필요에 따라 조정해 드리겠습니다.
그런 다음 관심 있는 파일을 보관할 (일반) 배열을 선언합니다. 다음 for
루프는 10개의 최신 inode를 반복하고 해당 파일 이름을 배열에 추가합니다. 마지막 10개의 inode는 이전과 동일한 와일드카드를 확장하여 결정되지만, 필드 #1에서 수정 시간(세대 이후 초)과 inode만 수정 시간(가장 큰 것/최신 것부터)으로 정렬한 후 inode를 제거합니다. 필드 #2를 실행 awk
하고 처음 10개의 inode를 가져옵니다 head
.
데모로서 이 코드는 다양한 파일 이름에 안전합니다.
for i in $(seq 1 10); do touch $RANDOM.jpg $RANDOM.png $RANDOM.txt; sleep 1.1; done
touch x.jpg '[x].jpg' 'a?b.jpg' 'a*b.jpg' '$( echo boom ).jpg'
touch single\'quote.jpg double\"quote back\\slash.jpg '*.jpg' ②.jpg
...출력은 다음과 같습니다.
declare -a wantedfiles=([0]="②.jpg" [1]="*.jpg" [2]="single'quote.jpg" [3]="back\\slash.jpg" [4]=$'X\240Y.jpg' [5]="[x].jpg" [6]="a?b.jpg" [7]="a*b.jpg" [8]="\$( echo boom ).jpg" [9]="25396.jpg")
$RANDOM
(나타나는 내용에 따라 마지막 파일 이름을 조정하십시오).