diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..c3f502a
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 디폴트 무시된 파일
+/shelf/
+/workspace.xml
+# 에디터 기반 HTTP 클라이언트 요청
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/backup.iml b/.idea/backup.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/backup.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..44ab3ba
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/backup b/backup
new file mode 100755
index 0000000..155bb61
Binary files /dev/null and b/backup differ
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..5dd4e88
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module backup
+
+go 1.24.5
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..75348ea
--- /dev/null
+++ b/main.go
@@ -0,0 +1,104 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "time"
+)
+
+func main() {
+
+ // 위치 인자 처리
+ if len(os.Args) < 3 {
+ fmt.Println("사용법: backup <원본경로> <백업경로> [옵션]")
+ os.Exit(1)
+ }
+ src := os.Args[1]
+ dst := os.Args[2]
+
+ // flag 인자 정의 (3번째 인자부터 처리)
+ fs := flag.NewFlagSet("backup", flag.ExitOnError)
+
+ groupBy := fs.String("group-by", "", "백업 폴더 구조 기준: year, mon, day, hour, min, sec")
+ snapshot := fs.String("snapshot", "", "스냅샷 기준: y, ym, ymd")
+ dryRun := fs.Bool("dry-run", false, "복사하지 않고 어떤 파일이 복사되는지 출력")
+ verbose := fs.Bool("verbose", false, "복사 로그 자세히 출력")
+ force := fs.Bool("force", false, "속성 무시하고 무조건 덮어쓰기")
+
+ _ = fs.Parse(os.Args[3:]) // 옵션 인자 처리
+
+ now := time.Now()
+
+ // 스냅샷 폴더 이름 생성
+ var snapshotFolder string
+ switch *snapshot {
+ case "y":
+ snapshotFolder = fmt.Sprintf("%d", now.Year())
+ case "ym":
+ snapshotFolder = fmt.Sprintf("%d%02d", now.Year(), int(now.Month()))
+ case "ymd":
+ snapshotFolder = fmt.Sprintf("%d%02d%02d", now.Year(), int(now.Month()), now.Day())
+ case "":
+ // 없음
+ default:
+ fmt.Printf("오류: 지원하지 않는 snapshot 옵션입니다: %s\n", *snapshot)
+ os.Exit(1)
+ }
+
+ // 출력 확인
+ // 그룹 폴더 이름 생성
+ fmt.Println("원본 경로:", src)
+ fmt.Println("백업 경로:", dst)
+ backupPath := dst
+ if *groupBy != "" {
+ fmt.Println("백업 그룹 기준:", *groupBy)
+ if *groupBy != "" {
+ backupPath = getGroupByFolder(dst, *groupBy, now)
+ }
+ // 이후에 backupPath 폴더를 생성하고, 파일 복사 진행
+ fmt.Println("최종 백업 경로:", backupPath)
+ }
+ if *snapshot != "" {
+ fmt.Println("스냅샷 폴더 이름:", snapshotFolder)
+ }
+ if *dryRun {
+ fmt.Println("Dry-run 모드 활성화됨")
+ }
+ if *verbose {
+ fmt.Println("Verbose 모드 활성화됨")
+ }
+ if *force {
+ fmt.Println("Force 모드 활성화됨")
+ }
+
+ // 이후 로직: 폴더 생성, 복사 등...
+
+}
+
+// groupBy 옵션에 따른 폴더 경로 생성 함수
+func getGroupByFolder(basePath, groupBy string, t time.Time) string {
+ folder := basePath
+
+ switch groupBy {
+ case "year":
+ folder = fmt.Sprintf("%s/%d", folder, t.Year())
+ case "mon":
+ folder = fmt.Sprintf("%s/%d%02d", folder, t.Year(), t.Month())
+ case "day":
+ folder = fmt.Sprintf("%s/%d%02d%02d", folder, t.Year(), t.Month(), t.Day())
+ case "hour":
+ folder = fmt.Sprintf("%s/%d%02d%02d_%02d", folder, t.Year(), t.Month(), t.Day(), t.Hour())
+ case "min":
+ folder = fmt.Sprintf("%s/%d%02d%02d_%02d%02d", folder, t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute())
+ case "sec":
+ folder = fmt.Sprintf("%s/%d%02d%02d_%02d%02d%02d", folder, t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
+ case "":
+ // 아무것도 안함
+ default:
+ fmt.Printf("지원하지 않는 group-by 옵션입니다: %s\n", groupBy)
+ os.Exit(1)
+ }
+
+ return folder
+}