다음과 같이 tar를 사용하여 간단한 백업 스크립트를 설정하려고 합니다.
#!/bin/bash
TIME=`date +%F_%H-%M`
FILENAME=backup-$TIME.tar.gz
SRCDIR="~/PI/tutos/* ~/scripts/*"
DESTDIR=/media/sf_ubuntuSharedFolder/backups
tar cvpzf $FILENAME $SRCDIR
그러나 $SRCDIR을 사용하면 직접 확장하면 발생하지 않는 tar 오류가 발생합니다.
alex@ALeX-VirtualBox:~$ save
tar: ~/PI/tutos/*: Cannot stat: No such file or directory
tar: ~/scripts/*: Cannot stat: No such file or directory
쉘 변수를 사용하는 데 어떤 문제가 있습니까? 그렇지 않으면 폴더 목록을 한 줄로 tar에 어떻게 전달할 수 있습니까?
답변1
문제는 ~
-expansion이 변수가 확장될 때( $SRCDIR
따옴표가 없는 변수를 인용하는 경우) 수행되지 않으며, 큰따옴표 안에서(변수를 할당하는 경우) 수행되지 않는다는 것 입니다 SRCDIR
.
따옴표가 없으면 $SRCDIR
분할+글로브 연산자를 호출하게 됩니다. 즉, 스칼라 $SRCDIR
변수( )에 저장된 ~/PI/tutos/* ~/scripts/*
문자열을 먼저 $IFS
분할(기본값은 공백)한 후 각 단어를 와일드카드, 즉 파일 목록과 일치하도록 확장된 패턴으로 처리합니다.
~
홈 디렉토리로 확장되지 않기 때문에 다른 문자처럼 취급되므로 현재 디렉토리의 디렉토리가 될 디렉토리에서 파일을 찾습니다. 귀하의 경우에는 디렉토리가 존재하지 않습니다 ~
.~/PI/tutos
~
$SRCDIR
가장 좋은 방법은 배열을 만들고 할당 시 glob을 확장하는 것입니다.
SRCDIR=(~/PI/tutos/* ~/scripts/*) # ~ and globs expanded at this point
tar cvpzf "$FILENAME" "${SRCDIR[@]}"
Split+glob 연산자를 적용하는 것은 $FILENAME
의미가 없으므로 따옴표를 사용하여 비활성화합니다 $FILENAME
.
불일치가 있으면 ~/PI/tutos/*
그대로 유지되므로 계속 오류가 발생합니다 tar
. 이를 방지하려면 다음을 수행할 수 있습니다.
shopt -s nullglob # remove non-matching globs
SRCDIR=(~/PI/tutos/* ~/scripts/*)
if ((${#SRCDIR[@]} != 0)); then
tar cvpzf "$FILENAME" "${SRCDIR[@]}"
fi
다음을 수행하고 싶을 수도 있습니다.
SRCDIR="$HOME/PI/tutos/* $HOME/scripts/*"
tar cvpzf "$FILENAME" $SRCDIR
변수(예: $HOME
)는 큰따옴표로 확장되므로 $HOME
전역 문자나 $IFS
.
~
따옴표가 없고 처음이나 뒤에 있으면 s는 변수 할당에서 확장됩니다 :
(그래서 $PATH
, ... 와 $LD_LIBRARY_PATH
같은 변수 할당에서 작동합니다 PATH=~/bin:~/sbin
). 따라서 다음을 수행하고 싶을 수도 있습니다.
SRCDIR=~/PI/tutos/*:~/scripts/* # ~ (not globs) expanded here
IFS=:
tar cvpzf "$FILENAME" $SRCDIR
그러나 위와 마찬가지로 문자(이번에는 홈 디렉토리를 콜론으로 구분된 테이블로 정의하므로 가능성이 낮음 )나 전역 문자가 $HOME
포함되어 있으면 작동하지 않습니다 .$IFS
:
/etc/passwd