반응형
- (연습 예제) CP 명령어 사용 시 중복된 파일의 이름을 자동으로 변경하기
배시 쉘 스크립트 연습 예제 입니다. 아래와 같은 상황에서 중복된 파일의 이름을 자동으로 변경해주는 스크립트를 만드는것이 목표 입니다.
- /root/test 디렉토리의 jpg 파일을 /root/data/ 으로 복사
- /root/test2 디렉토리의 jpg 파일을 /root/data/ 으로 복사
- test 디렉토리의 파일과, test2 디렉토리의 파일 중 test1.jpg ~ test5.jpg 파일명이 같음
이러한 문제를 해결하기 위해 고민한 부분은 크게 다음과 같습니다.
- 파일명을 어떻게 바꿔야 할까? → 랜덤 문자열 생성
- 파일명을 변경 시 경로 제외를 어떻게 할까? → awk로 마지막 레코드만 출력 후 변수에 저장
- 쉘 스크립트에서 cp 명령어로 파일명이 중복된다는걸 어떻게 캐치할 수 있을까? → expect 사용
가장 문제가 되는것은 파일명 중복을 캐치하는 부분 인데, 파일명이 중복될 경우 "cp: overwrite" 프롬프트가 생성 됩니다. expect를 사용해 cp: overwrite 문자열이 확인될 경우 exit를 반환 합니다.
* expect를 사용하기 위해선 패키지를 설치해야 합니다. (yum -y install expect)
* exp 파일은 sh 명령이 아니라, expect 명령어로 파일을 실행해야 합니다.
* status code를 구분해 중복으로 판단될 경우 네이밍을 하기 위해 exit로 반환 합니다.
저는 아래와 같은 auto_overwrite.exp 파일을 생성 했습니다.
#!/usr/bin/expect -f
# timeout 시간 무제한
set timeout -1
# 쉘 스크립트에서 인자값으로 변수를 받아옴
set after_path [lindex $argv 0]
set item [lindex $argv 1]
# cp 명령 실행
spawn cp -i $item $after_path
# 특정 문자열 발생 시 exit 입력
expect "cp: overwrite* "
send "exit\r"
이제 중복 파일명을 확인할 수 있는 expect를 만들었으니, 쉘스크립트로 넘어 갑니다. 저의 경우 root 홈디렉토리 아래를 검색해 jpg로 끝나는 파일들을 file_name 이라는 변수에 배열로 담았습니다.
자세한 내용은 주석 처리한 내용을 확인하시면 됩니다.
#!/bin/bash
after_path="/root/data"
file_name=`find /root -name "*.jpg"`
## file_name의 배열들을 하나씩 꺼내가면서 반복중 실행
for item in ${file_name[*]}
do
## /root/item-name 파일에 저장 (절대 경로 파일명이 저장됨)
echo "$item" > /root/item-name
## 중복 파일을 네이밍하기 위한 랜덤 문자열 생성 후 변수에 저장
random_name=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | sed 1q)
## awk로 마지막 레코드(파일명)을 추출 후 변수에 저장
item_file_name=$(awk -F '/' '{ print $NF }' /root/item-name)
## 위에서 생성한 exp파일 실행, 뒤에 변수는 인자값 전달
expect /root/auto_overwrite.exp $after_path $item
## status code를 변수에 저장
state=`echo $?`
## status code 0 : Overwrite
if [ "$state" == "0" ]; then
## Overwrite가 발생한 경우 중복 파일로 인지하고 네이밍을 새로 진행
cp "$item" "$after_path"/"$item_file_name"-"$random_name"
## status code 1 : Success
elif [ "$state" == "1" ]; then
echo "Success"
fi
## 생성했던 item-name 파일 삭제
rm -rf /root/item-name
done
스크립트 실행 결과는 아래와 같습니다.
반응형