最後活躍 1756818083

修訂 42a73d03f6402954b2fce798a6ae2607832cd8ad

shp2pgsql_local.sh 原始檔案
1#!/bin/bash
2
3DB="yourDb" # 실제 데이터베이스 이름으로 변경
4USER="postgres" # 실제 PostgreSQL 사용자명으로 변경
5SCHEMA="yourSchema" # 스키마 이름
6TABLE="yourTable" # 생성할 테이블 이름
7
8# 대소문자 구분 문제 해결을 위해 소문자로 변환
9SCHEMA_LOWER=$(echo "$SCHEMA" | tr '[:upper:]' '[:lower:]')
10TABLE_LOWER=$(echo "$TABLE" | tr '[:upper:]' '[:lower:]')
11
12SRID_ORI=5186 # 원본 좌표계
13SRID_NEW=0 # 변환 좌표계 (0이면 좌표변환 안함)
14CHARSET="UTF-8" # 문자 인코딩
15
16SHP_DIR="./" # shp 파일들이 있는 디렉토리 경로
17MAX_JOBS=8 # 병렬 작업 수 (시스템 성능에 따라 조정)
18
19# 로그 파일 설정
20LOG_DIR="./" # 로그 디렉토리 (필요시 경로 변경)
21mkdir -p "$LOG_DIR" # 로그 디렉토리가 없으면 생성
22LOG_FILE="$LOG_DIR/shp_import_$(date '+%Y%m%d_%H%M%S').log"
23
24# 로그 함수 정의
25logger() {
26 echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
27}
28
29# job control 함수 (병렬 처리 제한)
30function wait_for_jobs() {
31 local current_jobs
32 while true; do
33 current_jobs=$(jobs -rp | wc -l)
34 if [ "$current_jobs" -lt "$MAX_JOBS" ]; then
35 break
36 fi
37 sleep 0.5
38 done
39}
40
41# append 함수 정의
42function import_append() {
43 SHP="$1"
44 BASENAME=$(basename "$SHP")
45
46 # 처리 시작 시간 기록
47 FILE_START_TIME=$(date '+%Y-%m-%d %H:%M:%S')
48 FILE_START_TIMESTAMP=$(date +%s)
49
50 logger "🚀 [시작] $BASENAME 처리 시작: $FILE_START_TIME"
51
52 # 좌표변환 여부에 따라 shp2pgsql 명령어 결정
53 if [ "$SRID_NEW" -ne 0 ]; then
54 OUTPUT=$(shp2pgsql -W "$CHARSET" -s $SRID_ORI:$SRID_NEW -a "$SHP" $SCHEMA_LOWER.$TABLE_LOWER | psql -U "$USER" -d "$DB" 2>&1)
55 else
56 OUTPUT=$(shp2pgsql -W "$CHARSET" -s $SRID_ORI -a "$SHP" $SCHEMA_LOWER.$TABLE_LOWER | psql -U "$USER" -d "$DB" 2>&1)
57 fi
58 EXIT_CODE=$?
59
60 # 처리 종료 시간 기록
61 FILE_END_TIME=$(date '+%Y-%m-%d %H:%M:%S')
62 FILE_END_TIMESTAMP=$(date +%s)
63 FILE_DURATION=$((FILE_END_TIMESTAMP - FILE_START_TIMESTAMP))
64
65 # 파일별 소요시간을 시:분:초 형식으로 변환
66 FILE_HOURS=$((FILE_DURATION / 3600))
67 FILE_MINUTES=$(((FILE_DURATION % 3600) / 60))
68 FILE_SECONDS=$((FILE_DURATION % 60))
69
70 # 1보다 작으면 0으로 표시
71 if [ $FILE_HOURS -lt 1 ]; then FILE_HOURS=0; fi
72 if [ $FILE_MINUTES -lt 1 ]; then FILE_MINUTES=0; fi
73
74 if [ $EXIT_CODE -eq 0 ]; then
75 logger "✅ [완료] $BASENAME 처리 완료: $FILE_END_TIME (소요: ${FILE_HOURS}시간 ${FILE_MINUTES}${FILE_SECONDS}초)"
76 else
77 logger "❌ [실패] $BASENAME 처리 실패: $FILE_END_TIME (소요: ${FILE_HOURS}시간 ${FILE_MINUTES}${FILE_SECONDS}초)"
78
79 # 오류 메시지만 추출하여 로그에 기록
80 ERROR_MSG=$(echo "$OUTPUT" | grep -E "(ERROR|FATAL|WARNING|오류|실패|실패했습니다)" || echo "$OUTPUT")
81 if [ -n "$ERROR_MSG" ]; then
82 logger "⚠️ 오류 내용: $ERROR_MSG"
83 echo "=== $BASENAME 처리 오류 상세 내용 ===" >> "$LOG_FILE"
84 echo "$OUTPUT" >> "$LOG_FILE"
85 echo "=====================================" >> "$LOG_FILE"
86 fi
87
88 logger "🔄 다음 파일 처리를 계속 진행합니다."
89 fi
90}
91
92# 시작 시간 기록
93START_TIME=$(date '+%Y-%m-%d %H:%M:%S')
94START_TIMESTAMP=$(date +%s)
95
96
97# SHP 디렉토리 및 파일 존재 확인
98if [ ! -d "$SHP_DIR" ]; then
99 logger "❌ 오류: SHP 디렉토리가 존재하지 않습니다: $SHP_DIR"
100 exit 1
101fi
102
103SHP_COUNT=$(find "$SHP_DIR" -name "*.shp" | wc -l)
104if [ $SHP_COUNT -eq 0 ]; then
105 logger "❌ 오류: SHP 파일이 없습니다: $SHP_DIR"
106 exit 1
107fi
108logger "📁 발견된 SHP 파일 수: $SHP_COUNT개"
109
110# 필수 변수 검증
111if [ -z "$DB" ]; then
112 logger "❌ 오류: DB 변수가 설정되지 않았습니다. 스크립트 상단에서 DB 변수를 설정해주세요."
113 exit 1
114fi
115
116if [ -z "$TABLE" ]; then
117 logger "❌ 오류: TABLE 변수가 설정되지 않았습니다. 스크립트 상단에서 TABLE 변수를 설정해주세요."
118 exit 1
119fi
120
121logger "📋 설정된 변수:"
122logger " - 데이터베이스: $DB"
123logger " - 사용자: $USER"
124logger " - 스키마: $SCHEMA"
125logger " - 테이블: $TABLE"
126
127# PostgreSQL 연결 테스트
128if ! psql -U "$USER" -d "$DB" -c "SELECT 1;" >/dev/null 2>&1; then
129 logger "❌ 오류: PostgreSQL 연결 실패. 데이터베이스 연결을 확인해주세요."
130 exit 1
131fi
132logger "✅ PostgreSQL 연결 성공"
133
134# 좌표계 설정 확인 및 로깅
135if [ "$SRID_NEW" -ne 0 ]; then
136 logger "🗺️ 좌표변환 모드: $SRID_ORI$SRID_NEW"
137else
138 logger "🗺️ 원본좌표계 사용: $SRID_ORI"
139fi
140
141logger "=================================="
142logger "🚀 Import 시작: $START_TIME"
143logger "=================================="
144
145# 테이블 존재 여부 확인
146logger "🔍 테이블 존재 여부 확인 중: $SCHEMA_LOWER.$TABLE_LOWER"
147
148# 테이블 존재 여부를 더 안정적으로 확인 (소문자로 비교)
149TABLE_EXISTS=$(psql -U "$USER" -d "$DB" -t -c "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = '$SCHEMA_LOWER' AND table_name = '$TABLE_LOWER');" 2>/dev/null | xargs)
150
151logger "🔍 테이블 존재 확인 결과: '$TABLE_EXISTS'"
152
153# 모든 SHP 파일을 배열로 수집 (공백이 포함된 파일명도 안전하게 처리)
154mapfile -t SHP_FILES < <(find "$SHP_DIR" -name "*.shp" | sort)
155TOTAL_FILES=${#SHP_FILES[@]}
156
157# 배열이 비어있거나 null인 경우 체크
158if [ ${#SHP_FILES[@]} -eq 0 ] || [ -z "${SHP_FILES[0]}" ]; then
159 logger "❌ 오류: 유효한 SHP 파일을 찾을 수 없습니다."
160 exit 1
161fi
162
163if [ "$TABLE_EXISTS" = "t" ]; then
164 logger "📋 테이블 $SCHEMA_LOWER.$TABLE_LOWER이 이미 존재합니다. Append 모드로 진행합니다."
165 logger "🔄 총 $TOTAL_FILES개 파일을 append 모드로 처리합니다..."
166
167 # 모든 파일을 append 모드로 병렬 처리
168 for shp in "${SHP_FILES[@]}"; do
169 if [ -n "$shp" ]; then
170 wait_for_jobs
171 import_append "$shp" &
172 logger "🔄 백그라운드 작업 시작: $(basename "$shp")"
173 fi
174 done
175 wait
176 logger "✅ 모든 append 작업 완료"
177else
178 logger "📋 테이블 $SCHEMA_LOWER.$TABLE_LOWER이 존재하지 않습니다. 새로 생성합니다."
179 logger "🔄 총 $TOTAL_FILES개 파일을 처리합니다..."
180
181 # 첫 번째 파일로 테이블 생성
182 if [ $TOTAL_FILES -gt 0 ]; then
183 FIRST_FILE="${SHP_FILES[0]}"
184 FIRST_BASENAME=$(basename "$FIRST_FILE")
185
186 # 테이블 생성 시작 시간 기록
187 TABLE_START_TIME=$(date '+%Y-%m-%d %H:%M:%S')
188 TABLE_START_TIMESTAMP=$(date +%s)
189
190 logger "🚀 [시작] 테이블 생성 시작: $FIRST_BASENAME - $TABLE_START_TIME"
191
192 # 좌표변환 여부에 따라 shp2pgsql 명령어 결정
193 if [ "$SRID_NEW" -ne 0 ]; then
194 OUTPUT=$(shp2pgsql -W "$CHARSET" -s $SRID_ORI:$SRID_NEW "$FIRST_FILE" $SCHEMA_LOWER.$TABLE_LOWER | psql -U "$USER" -d "$DB" 2>&1)
195 else
196 OUTPUT=$(shp2pgsql -W "$CHARSET" -s $SRID_ORI "$FIRST_FILE" $SCHEMA_LOWER.$TABLE_LOWER | psql -U "$USER" -d "$DB" 2>&1)
197 fi
198 EXIT_CODE=$?
199
200 # 테이블 생성 종료 시간 기록
201 TABLE_END_TIME=$(date '+%Y-%m-%d %H:%M:%S')
202 TABLE_END_TIMESTAMP=$(date +%s)
203 TABLE_DURATION=$((TABLE_END_TIMESTAMP - TABLE_START_TIMESTAMP))
204
205 # 테이블 생성 소요시간을 시:분:초 형식으로 변환
206 TABLE_HOURS=$((TABLE_DURATION / 3600))
207 TABLE_MINUTES=$(((TABLE_DURATION % 3600) / 60))
208 TABLE_SECONDS=$((TABLE_DURATION % 60))
209
210 # 1보다 작으면 0으로 표시
211 if [ $TABLE_HOURS -lt 1 ]; then TABLE_HOURS=0; fi
212 if [ $TABLE_MINUTES -lt 1 ]; then TABLE_MINUTES=0; fi
213
214 if [ $EXIT_CODE -eq 0 ]; then
215 logger "✅ [완료] 테이블 생성 완료: $TABLE_END_TIME (소요: ${TABLE_HOURS}시간 ${TABLE_MINUTES}${TABLE_SECONDS}초)"
216
217 # 나머지 파일들을 append 모드로 병렬 처리
218 if [ $TOTAL_FILES -gt 1 ]; then
219 logger "🔄 나머지 $((TOTAL_FILES - 1))개 파일을 append 모드로 병렬 처리합니다..."
220 for ((i=1; i<TOTAL_FILES; i++)); do
221 if [ -n "${SHP_FILES[i]}" ]; then
222 shp="${SHP_FILES[i]}"
223 wait_for_jobs
224 import_append "$shp" &
225 logger "🔄 백그라운드 작업 시작: $(basename "$shp")"
226 fi
227 done
228 wait
229 logger "✅ 모든 append 작업 완료"
230 fi
231 else
232 logger "❌ [실패] 테이블 생성 실패: $TABLE_END_TIME (소요: ${TABLE_HOURS}시간 ${TABLE_MINUTES}${TABLE_SECONDS}초)"
233 echo "$OUTPUT" >> "$LOG_FILE"
234 exit 1
235 fi
236 else
237 logger "❌ 오류: 처리할 SHP 파일이 없습니다."
238 exit 1
239 fi
240fi
241
242# 병렬 처리 완료 확인 및 요약
243logger "🔄 병렬 처리 완료 확인 중..."
244logger "📊 처리된 파일 수: $TOTAL_FILES개"
245
246# 데이터 입력 완료 시간 기록
247DATA_END_TIME=$(date '+%Y-%m-%d %H:%M:%S')
248DATA_END_TIMESTAMP=$(date +%s)
249DATA_DURATION=$((DATA_END_TIMESTAMP - START_TIMESTAMP))
250
251# 데이터 입력 시간을 시:분:초 형식으로 변환
252DATA_HOURS=$((DATA_DURATION / 3600))
253DATA_MINUTES=$(((DATA_DURATION % 3600) / 60))
254DATA_SECONDS=$((DATA_DURATION % 60))
255
256# 1보다 작으면 0으로 표시
257if [ $DATA_HOURS -lt 1 ]; then DATA_HOURS=0; fi
258if [ $DATA_MINUTES -lt 1 ]; then DATA_MINUTES=0; fi
259
260# 3. (선택) 인덱스 재생성 (권장: 한 번에 생성)
261INDEX_START_TIME=$(date '+%Y-%m-%d %H:%M:%S')
262INDEX_START_TIMESTAMP=$(date +%s)
263
264logger "🔍 공간 인덱스 생성 시작: $INDEX_START_TIME"
265
266# 공간 인덱스 생성 (PostGIS 확장이 활성화되어 있어야 함)
267INDEX_OUTPUT=$(psql -U "$USER" -d "$DB" -c "CREATE INDEX IF NOT EXISTS ${TABLE_LOWER}_geom_idx ON $SCHEMA_LOWER.$TABLE_LOWER USING GIST (geom);" 2>&1)
268INDEX_EXIT_CODE=$?
269
270if [ $INDEX_EXIT_CODE -eq 0 ]; then
271 logger "✅ Spatial index created successfully"
272else
273 logger "❌ Failed to create spatial index"
274
275 # 오류 메시지만 추출하여 로그에 기록
276 INDEX_ERROR_MSG=$(echo "$INDEX_OUTPUT" | grep -E "(ERROR|FATAL|WARNING|오류|실패|실패했습니다)" || echo "$INDEX_OUTPUT")
277 if [ -n "$INDEX_ERROR_MSG" ]; then
278 logger "⚠️ 인덱스 생성 오류 내용: $INDEX_ERROR_MSG"
279 echo "=== 공간 인덱스 생성 오류 상세 내용 ===" >> "$LOG_FILE"
280 echo "$INDEX_OUTPUT" >> "$LOG_FILE"
281 echo "=====================================" >> "$LOG_FILE"
282 fi
283
284 logger "⚠️ PostGIS 확장이 활성화되어 있는지 확인하세요: CREATE EXTENSION IF NOT EXISTS postgis;"
285 logger "🔄 인덱스 생성에 실패했지만 스크립트는 계속 진행됩니다."
286fi
287
288# 인덱스 재생성 완료 시간 기록
289INDEX_END_TIME=$(date '+%Y-%m-%d %H:%M:%S')
290INDEX_END_TIMESTAMP=$(date +%s)
291INDEX_DURATION=$((INDEX_END_TIMESTAMP - INDEX_START_TIMESTAMP))
292
293# 인덱스 재생성 시간을 시:분:초 형식으로 변환
294INDEX_HOURS=$((INDEX_DURATION / 3600))
295INDEX_MINUTES=$(((INDEX_DURATION % 3600) / 60))
296INDEX_SECONDS=$((INDEX_DURATION % 60))
297
298# 1보다 작으면 0으로 표시
299if [ $INDEX_HOURS -lt 1 ]; then INDEX_HOURS=0; fi
300if [ $INDEX_MINUTES -lt 1 ]; then INDEX_MINUTES=0; fi
301
302logger "=================================="
303logger "✅ 작업 완료"
304logger "📋 대상테이블: $SCHEMA_LOWER.$TABLE_LOWER"
305if [ "$SRID_NEW" -ne 0 ]; then
306 logger "🗺️ 좌표계: $SRID_ORI$SRID_NEW (변환됨)"
307else
308 logger "🗺️ 좌표계: $SRID_ORI (원본)"
309fi
310logger "⏱️ 데이터 입력 소요시간: ${DATA_HOURS}시간 ${DATA_MINUTES}${DATA_SECONDS}"
311logger "⏱️ 공간 인덱스 소요시간: ${INDEX_HOURS}시간 ${INDEX_MINUTES}${INDEX_SECONDS}"
312logger "=================================="