| Server IP : 119.195.102.159 / Your IP : 216.73.217.134 Web Server : nginx/1.18.0 System : Linux picell 5.15.0-181-generic #191-Ubuntu SMP Fri May 22 19:09:02 UTC 2026 x86_64 User : altablue ( 1000) PHP Version : 8.3.31 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /tmp/ |
Upload File : |
#!/usr/bin/env bash
set -Eeuo pipefail
usage() {
cat <<'USAGE'
사용법:
cd /home2/사이트/wp-content
sudo /home/altablue/site_copy.sh [옵션] 원본 [원본 ...]
옵션:
-d DIR 현재 폴더 대신 DIR 안으로 복사
-n 실제 변경 없이 미리보기
-h 도움말
폴더 원본은 같은 이름의 대상 폴더에 병합합니다. 기존 파일은 갱신하지만
대상에만 있는 파일은 삭제하지 않습니다.
USAGE
}
fail() {
echo "❌ $*" >&2
exit 1
}
DEST_INPUT="$PWD"
DRY_RUN=0
while getopts ":d:nh" option; do
case "$option" in
d) DEST_INPUT="$OPTARG" ;;
n) DRY_RUN=1 ;;
h) usage; exit 0 ;;
:) fail "-$OPTARG 옵션에 값이 필요합니다." ;;
\?) fail "지원하지 않는 옵션입니다: -$OPTARG" ;;
esac
done
shift $((OPTIND - 1))
(( EUID == 0 )) || fail "sudo로 실행해야 소유권을 맞출 수 있습니다."
(( $# > 0 )) || { usage; fail "복사할 파일이나 폴더를 지정하세요."; }
command -v rsync >/dev/null 2>&1 || fail "rsync가 설치되어 있지 않습니다."
DEST_DIR="$(readlink -e -- "$DEST_INPUT" 2>/dev/null || true)"
[[ -n "$DEST_DIR" && -d "$DEST_DIR" ]] || fail "대상 폴더가 없습니다: $DEST_INPUT"
case "$DEST_DIR" in
/home/*|/home2/*) ;;
*) fail "대상은 /home 또는 /home2 아래여야 합니다: $DEST_DIR" ;;
esac
SITE_GROUP="$(stat -c '%G' -- "$DEST_DIR")"
[[ "$SITE_GROUP" == site_* ]] \
|| fail "현재 대상 폴더가 사이트 그룹을 사용하지 않습니다: $DEST_DIR ($SITE_GROUP)"
SITE_GID="$(getent group "$SITE_GROUP" | cut -d: -f3)"
mapfile -t SITE_USERS < <(
getent passwd | awk -F: -v gid="$SITE_GID" '$4 == gid && $1 ~ /^wp_/ { print $1 }'
)
(( ${#SITE_USERS[@]} == 1 )) \
|| fail "사이트 PHP 사용자를 하나로 확정할 수 없습니다: $SITE_GROUP"
SITE_USER="${SITE_USERS[0]}"
RSYNC_ARGS=(
-a
--safe-links
"--chown=${SITE_USER}:${SITE_GROUP}"
"--chmod=Du=rwx,Dg=rwx,Do=rx,Dg+s,Fu=rw,Fg=rw,Fo=r"
)
(( DRY_RUN == 1 )) && RSYNC_ARGS+=(--dry-run --itemize-changes)
echo "대상 폴더 : $DEST_DIR"
echo "적용 소유권 : ${SITE_USER}:${SITE_GROUP}"
(( DRY_RUN == 1 )) && echo "실행 방식 : 미리보기(변경 없음)"
echo "----------------------------------------------------"
for SOURCE_INPUT in "$@"; do
SOURCE_PATH="$(readlink -e -- "$SOURCE_INPUT" 2>/dev/null || true)"
[[ -n "$SOURCE_PATH" ]] || fail "원본이 없습니다: $SOURCE_INPUT"
[[ -r "$SOURCE_PATH" ]] || fail "원본을 읽을 수 없습니다: $SOURCE_PATH"
case "$SOURCE_PATH" in
/home/*|/home2/*) ;;
*) fail "원본은 /home 또는 /home2 아래여야 합니다: $SOURCE_PATH" ;;
esac
SOURCE_NAME="$(basename -- "$SOURCE_PATH")"
TARGET_PATH="${DEST_DIR}/${SOURCE_NAME}"
case "${DEST_DIR}/" in
"${SOURCE_PATH}/"*) fail "원본 폴더 안으로 재귀 복사할 수 없습니다: $SOURCE_PATH" ;;
esac
if [[ -d "$SOURCE_PATH" ]]; then
if (( DRY_RUN == 0 )); then
install -d -m 2775 -o "$SITE_USER" -g "$SITE_GROUP" "$TARGET_PATH"
fi
rsync "${RSYNC_ARGS[@]}" -- "$SOURCE_PATH/" "$TARGET_PATH/"
elif [[ -f "$SOURCE_PATH" ]]; then
rsync "${RSYNC_ARGS[@]}" -- "$SOURCE_PATH" "$DEST_DIR/"
else
fail "일반 파일 또는 폴더만 복사할 수 있습니다: $SOURCE_PATH"
fi
if (( DRY_RUN == 0 )) && [[ -e "$TARGET_PATH" ]]; then
find "$TARGET_PATH" -xdev -type f -name wp-config.php -exec chmod 0640 {} +
fi
echo "✅ $SOURCE_PATH -> $TARGET_PATH"
done
if (( DRY_RUN == 0 )); then
echo "✅ 복사와 사이트 권한 적용이 완료되었습니다."
fi