bash script2023. 4. 11. 11:49

반달가면 이글루에서 백업 - http://bahndal.egloos.com/543840

 

2014년 7월 11일과 2015년 3월 30일은 며칠 차이가 날까? date 명령을 이용해서 간단하게 계산할 수 있다. 우선 아래의 예시를 보자.

# 2014.7.11 KST -> 1970.1.1 00:00:00 UTC 이후 몇초가 흐른 시점인가?
date -d "20140711" "+%s"
1436540400

date 명령에서 -d 옵션은 현재 시간이 아니라 -d 옵션 이후에 지정된 인자를 기준으로 삼기 위한 것이다. 표시 형식을 "%s"로 지정하면 1970.1.1 00:00:00 UTC 이후 몇초가 지난 시점인지 알려준다.

처음에 제시한 문제로 돌아가서 계산 방법을 생각해 보자. 2014년 7월 11일을 "%s" 형식으로 바꾸고 2015년 3월 30일을 마찬가지로 "%s" 형식으로 바꾼다. 그 다음 두 값의 차이를 구하면 두 날짜의 시간차(단위:초)가 된다.

초 단위의 시간차를 일 단위로 환산하려면 86400으로 나누면 되겠다(1일=86400초). 이 계산은 bc 명령을 이용하면 된다. 아래의 예시를 보자.

# 날짜를 1970.1.1 자정을 기준으로 초 단위로 환산
first_date=`date -d "20140711" "+%s"`
second_date=`date -d "20150330" "+%s"`
# 두 날짜의 차이 계산 (단위: 일)
diff_date=`echo "($second_date - $first_date) / 86400" | bc`
echo "날짜 차이(일): $diff_date"

비슷한 문제를 하나 더 생각해 보자. 2014년 7월 11일 오후 2시 10분 33초와 2015년 3월 30일 오전 11시 35분 11초는 몇시간 차이가 나는 것일까? 초 단위로 계산한 값을 이번에는 3600으로 나누면 된다(1시간=3600초). 아래의 예시를 보자.

first_date=`date -d "20140711 14:10:33" "+%s"`
second_date=`date -d "20150330 11:35:11" "+%s"`
diff_hour=`echo "($second_date - $first_date) / 3600" | bc`
echo "날짜 차이(시간): $diff_hour"

언뜻 보면 위의 계산법이 유효하기 위해 대상 날짜가 반드시 UTC 기준으로 1970년 1월 1일 이후가 되어야 할 것 같기도 하지만, 그 이전의 날짜로도 계산이 다 된다. -d 옵션에서 지정한 날짜가 1969년 12월 31일 이전이라면 "%s" 형식으로 표시할 때 음수(-)로 표시되기 때문이다. 만약 이 값이 -10이라면 1970년 1월 1일 자정이 되기 10초전이라는 뜻이다.

728x90
Posted by 반달가면
bash script2023. 4. 11. 11:42

 

반달가면 이글루에서 백업 - http://bahndal.egloos.com/540667

 

파일에서 특정한 문자열을 검색해야 하는데 하나의 항목에 대한 내용이 여러줄로 되어 있는 경우가 있다. 예를 들어 전화번호부에서 특정인물의 전화번호를 grep 명령으로 찾으려는데 아래와 같이 생긴 경우다.

cat my_file.txt
name: john
phone: 010-123-4556

name: jane
phone: 010-345-1234
...

리눅스에서 검색을 염두에 두고 있다면 처음부터 이런 형식으로 만들지 않는 것이 좋겠지만, 특정 어플리케이션의 출력이 원래 저런 형태를 띠고 있을 때도 있고 아무튼 위와 같은 형태의 파일을 다룰 일이 간혹 생기다 보니, 아래와 같은 스크립트를 사용하고 있다. 반복되는 항목이 여러줄로 나타날 경우 한 항목당 한줄씩으로 바꾸는 방법이다. 위에서 언급한 my_file.txt 파일을 가지고 이름과 전화번호를 한줄에 넣고 탭(tab)으로 구분되도록 만든다.

# 결과 파일명을 res_file 변수에 할당
res_file="my_file.modified.txt"
# sed 명령에 사용하기 위한 변수 prt
prt="p"
# my_file.txt가 몇줄인지 파악하여 max_line 변수에 할당
max_line=`cat my_file.txt | wc -l`
# my_file.txt 파일을 한줄씩 읽기 위한 for 반복문
for line_num in `seq 1 $max_line`
do
  # line_num번째 행을 cur_line 변수에 할당
  cur_line=`sed -n $line_num$prt my_file.txt`
  # 항목 구분자가 빈 줄이므로 빈 줄이 나타났는지 확인
  separator_check=`echo $cur_line | grep [[:graph:]] | wc -l`
  # separator_chek 변수값이 0이면 빈 줄이므로 줄바꿈, 아니면 줄바꿈 없이 현재 행을 추가하고 탭 추가
  if [[ $separator_check -eq 0 ]]
    then echo -e "\n" >> $res_file
    else echo -en "$cur_line\t" >> $res_file
  fi
done

파일을 한줄씩 읽어서(sed 명령), 빈 줄이면 줄바꿈을 추가하고(echo -e "\n") 아니면 해당 줄의 내용을 추가하되 줄바꿈 없이 탭을 추가하도록(echo -en "$cur_line\t") 한 것이다.  sed 명령에 대한 좀 더 자세한 내용과 echo 명령의 옵션은 이전 게시물을 참고하자. sed 명령에 대한 내용은 여기로, echo 명령에 대한 내용은 여기로.

항목 사이의 경계가 빈 줄이 아니라 다른 문자열이라면 구분자 확인을 위한 separator_chek 변수값을 할당 할 때 그에 맞게 grep 명령과 이후의 if 조건문을 바꿔 주면 되겠다. 예를 들어 my_file.txt에서 빈 줄이 없다면 항목 시작 문자열을 이용할 수 있다. 여기서는 "name:"이므로, 해당 부분이 아래와 같이 바뀌어야 할 것이다.

  separator_check=`echo $cur_line | grep "^name: " | wc -l`
  if [[ $separator_check -eq 1 ]]
    then echo -en "\n$cur_line\t" >> $res_file
    else echo -en "$cur_line\t"
  fi
    ...
 
위와 같이 작업해서 my_file.modified.txt 파일을 만들고 나면 좀 더 쉽게 검색을 할 수 있다.

# john의 전화번호 찾기
cat my_file.modified.txt | grep john
name: john    phone:  010-123-4556

728x90
Posted by 반달가면
bash script2023. 4. 11. 11:38

반달가면 이글루에서 백업 - http://bahndal.egloos.com/540410

 

특정 디렉토리 안에 있는 일부 파일들이 차지하고 있는 공간을 계산하기 위한 방법이다. 예를 들어 ~/documents 디렉토리에서 pdf 파일이 용량 합계가 얼마인지 구하는 것. (특정 디렉토리의 디스크 사용량을 알려주는 du 명령 보다  좀 더 세밀한 작업을 필요로 할 때 요긴하다.)

우선 아래의 예시를 보자.

# ~/documents 디렉토리에서 pdf 파일을 찾아 파일 정보 표시
find ~/documents -type f -name "*.pdf" -ls
 
~/documents 디렉토리와 그 하위 디렉토리에 대해서 파일(-type f)을 찾되 이름이 .pdf로 끝나는 것(-name "*.pdf")만 고른다. 그리고 이 파일들에 대한 정보를 표시(-ls)한다. -ls 옵션을 사용하면 ls -l 명령으로 출력한 것과 유사한 결과를 볼 수 있다. 하위 디렉토리를 검색 대상에서 제외하거나 범위를 지정하려면 -maxdepth 옵션을 추가하면 되겠다.

# pdf 파일 찾기. 하위 디렉토리 제외
find ~/documents -maxdepth 1 -type f -name "*.pdf" -ls

위의 find 명령에 대한 결과값을 보면 파일 용량 정보가 통상 7번째 항목일 것이다. 이제 awk 명령을 이용해서 이 항목을 다 더하면 용량 합계를 구할 수 있다.

# ~/documents 디렉토리의 pdf 파일 용량 합계 구하기
find ~/documents -maxdepth 1 -type f -name "*.pdf" -ls | awk '{ result += $7 } END { print result }'

awk 명령을 이용해서 find 명령의 결과중 7번째 항목($7)을 누적해서 result라는 변수에 저장하고(result += $7) 이 작업을 마친 후에(END) result 변수값을 출력(print result)하면 된다.

파이프(|)와 grep 명령을 조합해서 계산할 수도 있다. 아래의 예시를 보자.

# ~/documents 디렉토리의 pdf 파일을 찾아 파일 정보 표시
find ~/documents -type f | grep "\.pdf$" | xargs ls -l

위의 예시에서 ls -l 명령의 다섯번째 항목($5)에 파일 용량이 나타난다는 점을 이용해서 아래와 같이 계산한다.

# ~/documents 디렉토리의 pdf 파일을 찾아 용량 합계 계산
find ~/documents -type f | grep "\.pdf$" | xargs ls -l | awk '{ result += $5 } END { print result }'

 

728x90
Posted by 반달가면
bash script2023. 4. 11. 11:24

 

 

반달가면 이글루에서 백업 - http://bahndal.egloos.com/540184

 

일단, 리눅스 shell script에서 ftp 서버에 자동으로 접속하는 법은 예전에 이미 써 두었다. 이전 게시물을 참고하면 된다. 여기로

추가적으로, 자동접속해서 파일을 올리거나 가져오는 과정이 정상적으로 잘 종료되었는지를 확인하는 과정이 필요할 수 있다. 전송 도중에 네트워크 문제로 연결이 끊어졌는지 판단할 수 있는 간단한 방법은 FTP 접속 과정을 별도의 로그 파일로 남기고 이 내용을 확인하면 된다.

우선 ftp 자동접속을 하고 접속 이후 수행되는 내용을 ftp_log.txt 파일로 저장한다. 아래의 예시를 보자.

# 192.168.0.10 서버에 접속, 이후 과정은 ftp_log.txt에 저장
ftp -n -p 192.168.0.10 << SCRIPT > ftp_log.txt
  user john my_password
  binary
  put my_data.dat
  quit
SCRIPT

ftp에서 -p 옵션은 패시브 모드(passive mode)로 접속하기 위한 것이다. 액티브 모드(active mode)로 접속하려면 생략한다.

전송이 성공적으로 이루어졌다면, ftp_log.txt 파일에 대략 아래와 같은 내용이 포함되어야 정상이다.

...
ftp> put my_data.dat
local: my_data.dat remote: my_data.dat
200 PORT command successful.
150 Ok to send data
226 Transfer complete.
...

성공적으로 전송되었다면 "226 Transfer complete" 메세지가 있어야 한다. 메세지 내용은 서버에 따라 약간 차이가 있을 수 있으니 해당 ftp 서버에 접속해서 전송시험을 한번 해 보고 메세지 순서와 내용을 미리 확인해 보자.

이제 ftp_log.txt 파일의 내용에서 성공 확인 메세지 존재 여부를 확인하면 된다. 아래의 예시를 보자.

# ftp_log.txt 파일에서 전송 성공 메세지 확인
ftp_check=`cat ftp_log.txt | grep "^226 Transfer complete\." | wc -l`
if [[ $ftp_check -eq 1 ]]
then echo "my_data.dat 파일 전송 성공"
else echo "my_data.dat 파일 전송 실패"
fi

mput 명령으로 한꺼번에 여러개의 파일을 보낼 경우에는 "226 Transfer complete" 메세지의 수와 보낸 파일의 수가 같은지 점검하면 될 듯. 아래의 예시를 보자. ~/my_data 디렉토리 안에 있는 .dat 파일을 모두 전송하는 경우이다.

# 디렉토리 이동
cd ~/my_data
# ~/my_data 디렉토리에 .dat 파일이 몇개인지 파악하여 files_num 변수에 저장
files_num=`ls *.dat | wc -l`
# ftp 전송, ftp_log.txt 파일 생성
ftp -n -p 192.168.0.10 << SCRIPT > ftp_log.txt
  user john my_password
  binary
  prompt
  mput *.dat
  quit
SCRIPT
# ftp_log.txt 파일 확인
ftp_check=`cat ftp_log.txt | grep "^226 Transfer complete\." | wc -l`
if [[ $ftp_check -eq $files_num ]]
then echo ".dat 파일 전송 성공. (개수: $files_num)"
else echo ".dat 파일 전송 실패. 자세한 내용은 ftp_log.txt 파일을 참조하세요."
fi

-----
2020.11.13 추가

ftp 전송 이력이 파일에 제대로 저장되지 않는 경우 ftp 실행에 -v 옵션을 추가해 보자.

ftp -n -p -v 192.168.0.10 << SCRIPT > ftp_log.txt
...
SCRIPT

728x90
Posted by 반달가면