중복 가능성:
가장 오래된 파일을 이동하는 쉘 스크립트?
x
백업해야 하는 다른 디렉터리를 저장하는 백업 디렉터리가 있습니다 . 다른 디렉토리가 백업으로 이동되기 전에 실행되는 것이 필요합니다. 디렉토리 수에 도달했는지 확인하고 x
, 도달하면 가장 오래된 디렉토리를 삭제합니다.
이는 스크립트로 수행되어야 합니다 bash
.
답변1
ls
다음의 출력을 구문 분석합니다.신뢰할 수 없는.
대신 을 사용하여 find
디렉터리를 찾고 sort
타임스탬프별로 정렬하세요. 예를 들어:
IFS= read -r -d $'\0' line < <(find . -maxdepth 1 -type d -printf '%T@ %p\0' \
2>/dev/null | sort -z -n)
file="${line#* }"
# do something with $file here
이게 다 뭐하는 거야?
먼저, 이 명령은 현재 디렉터리( )의 모든 디렉터리를 find
찾습니다 . 그러나 현재 디렉터리( )의 하위 디렉터리인 모든 디렉터리는 검색하지 않습니다. 그런 다음 다음을 인쇄합니다..
-maxdepth 1
- 타임스탬프
- 공간
- 파일의 상대 경로
- 널 문자
타임스탬프가 중요합니다. 형식 %T@
지정자는 파일의 "마지막 수정 시간"(mtime)을 나타내는 와 분수 초를 포함하여 "1970년 이후의 초 수"를 나타내는 -printf
로 구분됩니다 .T
@
공백은 임의의 구분 기호일 뿐입니다. 파일의 전체 경로는 나중에 참조할 수 있도록 하기 위한 것이며, NULL 문자는 파일 이름에 잘못된 문자이므로 파일 경로 끝에 도달했는지 확인할 수 있게 해주는 종결자입니다. 문서.
2>/dev/null
사용자가 액세스할 수 없는 파일을 제외하도록 포함시켰지만 해당 파일이 제외되었다는 오류 메시지는 표시되지 않습니다.
이 명령의 결과 find
는 현재 디렉터리의 모든 디렉터리 목록입니다. 목록은 으로 파이프되어 다음을 sort
나타냅니다.
-z
NULL을 개행 문자가 아닌 줄 종결자로 처리합니다.-n
숫자순으로 정렬
1970년 이후 초 수가 항상 증가하므로 타임스탬프 수가 가장 적은 파일이 필요합니다. 첫 번째 결과 sort
는 가장 낮은 번호의 타임스탬프가 포함된 행이 됩니다. 남은 것은 파일 이름을 추출하는 것뿐입니다.
find
, 파이프라인의 결과는 sort
다음을 통과합니다.프로세스 교체to read
, 표준 입력에서 파일로 읽혀집니다.
read
변수를 공백으로 설정한 맥락에서 IFS
이는 공백이 구분 기호로 부적절하게 해석되지 않음을 의미합니다. 이스케이프 확장을 비활성화하고 줄 끝 구분 기호를 NULL로 만들어 파이프의 출력과 일치시킨다는 것을 read
알 수 있습니다 .-r
-d $'\0'
find
sort
첫 번째 데이터 블록은 타임스탬프와 공백이 앞에 오는 가장 오래된 디렉터리 경로를 나타내며 변수로 읽혀집니다 line
. 다음,매개변수 대체표현식과 함께 사용하면 #*
문자열 시작 부분부터 첫 번째 공백을 포함하여 모든 문자를 null로 바꿉니다. 이렇게 하면 수정 타임스탬프가 제거되고 파일의 전체 경로만 남습니다.
이 시점에서 파일 이름은 에 저장 $file
되며 rm -rf "$file"
.
더 쉬운 방법은 없을까요?
아니요. 더 간단한 접근 방식에는 결함이 있습니다.
and를 사용하여 ls -t
파이프 하면 tail
파일 이름에 줄바꿈이 포함된 파일이 중단됩니다. rm $(anything)
이름에 공백이 포함된 파일은 손상될 수 있습니다 . rm "$(anything)"
이름 뒤에 개행 문자가 있는 파일은 손상될 수 있습니다.
더 간단한 접근 방식으로 충분하다고 확신하는 특정 상황이 있을 수 있지만, 가능하다면 그러한 가정을 스크립트에 작성해서는 안 됩니다.
편집하다
#!/usr/bin/env bash
dir="$1"
min_dirs=3
[[ $(find "$dir" -maxdepth 1 -type d | wc -l) -ge $min_dirs ]] &&
IFS= read -r -d $'\0' line < <(find "$dir" -maxdepth 1 -printf '%T@ %p\0' 2>/dev/null | sort -z -n)
file="${line#* }"
ls -lLd "$file"
디렉터리 수를 먼저 확인하므로 문제에 대한 보다 완벽한 솔루션입니다.
답변2
다음과 같은 것을 사용할 수 있습니다.
#!/bin/sh
keep=3
while [ `ls -1 | wc -l` -gt $keep ]; do
oldest=`ls -c1 | head -1`
echo "remove $oldest"
rm -rf $oldest
done
사용하는 것이 find . -type d -maxdepth 1
더 나을 수도 있지만 ls
. 이는 디렉터리에 사용하는 명명 패턴에 따라 다릅니다. 자연스럽게 이름별로 올바르게 정렬된 경우 및 find
또는를 사용 하여 가장 오래된/최신 디렉토리를 가져올 수 있습니다. 이 방법은 정렬을 위해 ctime 속성을 사용합니다.sort
head
tail
ls
답변3
다음을 사용해 보세요:
rm $(ls -t1 | tail -n 1)