문맥
tar.gz 파일을 생성하고 이를 헤드리스 Linux 가상 머신의 dropbox 폴더로 전송하는 백업 스크립트를 실행하고 있습니다.
질문
스킴에 따라 이름이 지정된 파일 중 가장 오래된 파일을 검색하는 스크립트를 만드는 방법을 모르겠습니다 /root/Dropbox/apache2-backup-%Y-%m-%d-%H-%M
.
/root/Dropbox-archive/
그런 다음 Dropbox에 공간이 2GB밖에 없기 때문에 이 파일을 폴더로 옮기고 싶습니다 .
답변1
"쉬운" 솔루션
ls -1 /Dropbox/apache2-backup-*
이름, 즉 날짜별로 알파벳순으로 정렬해야 합니다(날짜는 가장 중요한 숫자가 왼쪽에 오도록 형식화되어 있으므로). 그런 다음 파이프를 통해 가장 오래된 파일을 가져올 수 있습니다 head -1
(파일 이름에 줄 바꿈이 없다고 가정). 일반적으로 파이핑을 사용하는 ls
것은 좋지 않은 생각이지만 이 경우 파일 이름에 특수 문자가 없다는 것을 알고 있으므로 괜찮습니다.
mv "$(ls -1 /Dropbox/apache2-backup-* | head -1)" /root/Dropbox-archive/
실수로 파일을 덮어쓰는 일이 없도록 mv --no-clobber
( 또는 )를 대신 사용하는 것이 좋습니다 .mv -n
"올바른" 솔루션
특수 문자가 정말 걱정된다면 다음을 대신 사용할 수 있습니다.
to_move="$(find /Dropbox -maxdepth 1 -type f -name 'apache2-backup-*' -print0 | sort -z | tr '\0\n' '\n\0' | head -1 | tr '\0\n' '\n\0')"
mv "$to_move" /root/Dropbox-archive/
설명하다
find /Dropbox -maxdepth 1 -type f -name 'apache2-backup-*' -print0
: 패턴( )과 일치하는 하위 디렉터리를 입력하지 않고 일반 파일(-type f
) 을 반환합니다 . 줄바꿈이 아닌 널 문자로 구분하세요 ./Dropbox
-maxdepth 1
-name 'apache2-backup-*'
-print0
| sort -z
:유형널 문자를 기반으로 합니다(모든 유형이 이를 수행할 수 있는 것은 아닙니다).| tr '\0\n' '\n\0'
:교환Null과 개행 문자는 헤드에서 처리됩니다.| head -1
: 첫 번째 줄로 돌아갑니다.| tr '\0\n' '\n\0'
: null 값과 개행 문자를 다시 바꿉니다.mv "$to_move" /root/Dropbox-archive/
: 움직여보자!
또는 한 줄로:
mv "$(find /Dropbox -maxdepth 1 -type f -name 'apache2-backup-*' -print0 | sort -z | tr '\0\n' '\n\0' | head -1 | tr '\0\n' '\n\0')" /root/Dropbox-archive/
답변2
가장 오래된 것만 옮기는 경우하나, 이것을 사용하십시오 :
_mv(){ mv -- "$1" /root/Dropbox-archive/; }
_mv /Dropbox/apache2-backup-*
하지만 제목에는 그런 내용이 나와 있지 않습니다.
처리 ls
출력이나쁜 생각, 더 나은 접근 방식은 다음과 같습니다.
if [ "$BASH" ]; then
# If you happen to use bash or any other shell that has some similar array:
move_first_things(){ mv -- "${@:0:50}" /root/Dropbox-archive/; }
else # Unfortunate POSIX way
# As long as copy-pasting is acceptable, loop-unrolling with
# `mv -- "$1" "$2" "$3"... /root/Dropbox-archive/` is better since it calls `mv` less.
move_first_things(){
local max=50 count=0
while [ "$count" -lt "$max" ]; do
mv -- "$1" /root/Dropbox-archive/
shift
: $((count = count + 1))
done
}
fi
출력은 다음과 같은 와일드카드로 인해 정렬됩니다 ls
.
move_first_things /Dropbox/apache2-backup-*
폴리스티렌: 이것은 실제로 외부 프로그램(mikeserv,여기에 설명되어 있습니다). 약간의 주의와 약간의 혼란만 더해지면 사람들은 안전하게 작업을 수행할 수 있습니다. 하지만 이 경우에도 여전히 예쁜 파일 이름을 사용하겠습니다.
폴리페닐렌 설파이드:don_crist가 일부 zshism을 언급했습니다. zsh는 함수, 매개변수 확장, 배열과 같은 익명 기능을 훌륭하게 지원합니다. 여전히 파일 이름 방식을 사용하면( bash
그러한 정렬 연산자가 없기 때문에) 전체 내용을 다음과 같이 작성할 수 있습니다 baks=( /Dropbox/apache2-backup-* ); mv "$baks" /root/Dropbox-archive/
(첫 번째 멤버만 제공하는 배열 참조) mv "${baks[@]:0:50}" /root/Dropbox-archive/
. 또는 여러 가지에 대해 실제로는 해당 래퍼보다 더 좋아 보입니다 . 기능이 더 좋습니다.
답변3
( IFS=/ # split on /
set -ef /Dropbox/apache2-backup* # set arg array to last glob
for f in $(\ls -rtd "$@";echo /) # iterate over sorted/split array
do [ -z "${f##D*}" ] || # ignore dirname
mv "${1%/*}/${f%?}" \
"/root${1%/*}-archive" # do sorted mv
done # do && break to do only one mv
)
어떤 이유로든 사람들은 를 사용하여 매개변수 목록을 안정적으로 정렬할 수 없다고 생각하는 것 같습니다 ls
. 내 생각엔 이 사람들이 개행 문자로 경로명을 분리하려고 하기 때문인 것 같습니다. 그러나 문제는 경로명이 줄 바꿈으로 구분되지 않는다는 것입니다. 결코 그런 적이 없습니다. 경로 이름 구분 기호 /
- 경로 이름 구분 기호이므로 개행 문자는 혼란을 야기할 뿐입니다. 출력을 안정적으로 구문 분석하려면 ls
출력을 올바르게 분할해야 합니다.
답변4
질문은 가장 오래된 파일을 지정했습니다. ls -rt
수정 시간을 기준으로 오래된 파일부터 정렬하여 파일을 나열합니다. 이 답변은 백업 파일을 식별하는 접두사 이외의 파일 이름 형식을 사용하지 않습니다. 여기에서는 파일 이름의 날짜 부분이 고려되지 않습니다.
mv "$(ls -tr /root/Dropbox/apache2-backup-*| head -1)" /root/Dropbox-archive/
파일 시간을 기준으로 정렬하는 것은 파일 이름을 기준으로 정렬하는 것보다 낫지 않으며 그 반대도 마찬가지입니다. 이는 대체로 개인 취향이며 상황과 문화에 따라 다릅니다.
"
두 경우 모두, 그리고 대부분의 경우 아래와 같이 명령 확장을 큰따옴표로 묶는 것이 더 안전합니다. "$( ... )"
이렇게 하면 파일 이름을 제외하고 백업 파일 파일 이름 등의 모든 특수 문자(공백, 구두점, 탭)를 처리합니다. 개행 문자를 포함합니다.