bash script (backup)2021. 9. 24. 16:50

 

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

 

특정 디렉토리에서 용량을 가장 많이 차지하고 있는 파일을 찾아야 할 때가 있다. 일일이 용량을 눈으로 확인해도 되지만 파일 수가 아주 많을 때는 좀 더 우아한(?) 방법을 찾아야 한다.

우선 정렬을 위한 sort 명령을 생각해 보자.

# 8 에서 11까지 출력하고 정렬
seq 8 11 | sort
10
11
8
9

 

seq 명령을 이용해서 8에서 11까지 출력한 후 이것을 sort 명령으로 정렬하면 출력한 수자를 문자로 간주하고 정렬하므로 위의 예시와 같은 결과가 나온다. 수자를 수자로 인식하기 위해서는 -g 옵션을 사용하면 된다.

seq 8 11 | sort -g
8
9
10
11

자, 이제 가장 큰 수부터 출력하도록 정렬 순서를 반대로 한다. -r 옵션을 사용하자.

seq 8 11 | sort -g -r
11
10
9
8

큰 파일들을 찾기 위한 준비가 끝났다. ls -l 명령으로 디렉토리에 있는 파일명과 크기를 같이 출력한 후에 awk 명령으로 파일 크기와 파일명만 골라내고, 이 결과값을 sort 명령으로 정렬한다.

# ~/my_dir 디렉토리의 파일 용량 TOP10 출력
ls -l ~/my_dir | grep "^\-" | awk '{print $5 "\t" $9}' | sort -g -r | head -10

 

ls -l 명령의 출력에서 디렉토리나 심볼릭 링크를 제외하고 파일만 골라내기 위해 '-' 부호로 시작하는 행만 선별하고(grep 명령)

파일 용량(5번째 항목)과 파일명(9번째 항목)만 골라서 탭(tab)을 구분자로 해서 출력한 후(awk 명령)

가장 용량이 큰 항목부터 출력하도록 정렬(sort 명령), 여기서 맨 처음 10개 행만 표시(head 명령)

용량을 많이 차지하고 있는 디렉토리를 찾고 싶다면 du 명령 이용하면 된다. 아래의 예시를 보자.

# ~/my_dir 디렉토리 하위에 있는 디렉토리 용량 TOP10 출력
du ~/my_dir | sort -g -r | head -10

 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2021. 7. 20. 16:32

 

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

 

문서(txt) 파일에서 중복되는 행(line)을 제거하는 방법은 두가지를 생각해 볼 수 있는데, 하나는 정렬한 후에 제거하는 것이고 나머지 하나는 정렬하지 않고 제거하는 것이다.

행 순서가 바뀌어도 문제가 없는 경우라면 sort 명령을 이용해서 정렬한 후에 중복을 제거하면 된다. -u 옵션을 사용하면 중복된 행이 제거된다. 아래의 예시를 보자.

 

# my_file.txt 내용 확인

cat my_file.txt

def

abc

abc

def

 

# 정렬 및 중복 제거

sort -u my_file.txt

abc

def

 

또는 아래와 같이 사용할 수도 있다. 결과는 동일하다.

 

cat my_file.txt | sort -u

 

그렇다면 행 순서를 바꾸지 않은 상태에서 중복된 행들만 제거하려면 어떻게 할까?

 

심오하고도 위대한 awk 명령을 이용하면 되겠다. 좀 복잡하긴 한데, 일단 아래의 예시를 보자.

 

# 정렬하지 않고 중복 제거

awk '!x[$0]++ {print $0}' my_file.txt

def

abc

 

awk의 기본 동작이 화면에 출력하는 것이기 때문에 {print $0} 부분은 생략해도 무관하다.

 

awk '!x[$0]++' my_file.txt

 

아래과 같이 해도 된다. 결과는 동일.

 

cat my_file.txt | awk '!x[$0]++'

 

'!x[$0]++ {print $0}' 이 표현이 나름 심오한데, awk의 배열(array)이 가진 특징을 생각해 보면 감을 잡을 수 있다. awk에서는 배열의 인덱스(index)가 반드시 0 이상의 정수일 필요가 없고 문자열도 인덱스가 된다. C언어에서는 x[0], x[1] 이렇지만 awk에서는 x[my name is john], x[foo] 이런 것이 가능하다. 게다가 배열의 최대 크기를 지정할 필요도 없다.

 

자, 그러면 위의 표현이 어떤 일을 하는지 생각해 보자. awk에서 행 전체를 지칭하는 변수는 $0이다. 즉, 한 행의 문자열을 x라는 배열의 인덱스로 사용하는 것이다. 차근차근 보면 대강 이렇다.

 

명령을 실행하면 awk는 우선 my_file.txt의 첫 행을 읽어서 배열을 만든다. 해당 변수의 값의 기본 초기값은 0이다. 위의 예시에서 첫 행은 def였다. 즉 x[def]=0 (false)

 

그런데 앞에 ! 기호가 있으니 해당 값의 역(inverse)을 취한다. !x[def]=1 (true)

 

조건값이 non-zero, 즉 0이 아니므로 지정된 명령을 실행한다. {print $0} (문자열 출력)

 

그리고 나서 x[def]++(post-increment)에 의해 x[def]의 값은 1이 된다. x[def]=1

 

my_file.txt의 두번째 행을 읽어서 동일한 절차를 수행한다. 두번째 행은 abc이므로 출력이 끝나고 나면 x[abc]=1

 

이런식으로 가다가 어떤 행을 읽었는데 문자열 def였다고 하자. 즉 중복이 발생한 것이다. 이전에 이미 x[def]=1이므로 !x[def]=0, 즉 조건값이 0(false)이므로 출력되지 않는다. 그리고나서 x[def]++에 따라 x[def]=2 이렇게 된다.

 

이런 원리로 행 순서가 바뀌지 않으면서 중복된 행만 깔끔하게 제거된 결과를 얻을 수 있다. 속도 역시 상당히 빠르다.

 

만약 행 전체가 아니라 첫번째 단어만 기준으로 삼아서 중복을 제거하고 싶다면 x[$0] 대신에 x[$1] 이렇게 바꾸면 된다. (두번째 단어라면 x[$2])

 

awk '!x[$1]++ {print $0}' my_file.txt

 

만약 첫번째 단어만 기준으로 삼아 중복을 제거한 후, 출력은 두번째 단어만 골라서 하고 싶다면 print 부분의 인자를 바꿔주면 되겠다. 아래와 같이 해 보자.

 

awk '!x[$1]++ {print $2}' my_file.txt

 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2021. 7. 13. 13:35

 

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

 

파일 내용을 출력하기 위해 주로 사용하는 cat 명령은 내용만 출력하고 파일명은 출력하지 않는다. 여러개의 파일 내용을 한꺼번에 확인하고 싶을 때는 파일명을 식별할 수 없기 때문에 불편한 경우가 생길 수 있다.

 

# .txt 확장자인 파일의 내용을 출력, 파일명은 출력되지 않음

cat *.txt

 

파일명을 같이 출력하고 싶다면 cat 명령 대신 head 명령을 사용하자. 여러개의 파일에 대해 적용했을 경우 파일명이 함께 출력된다. 원래 head 명령은 파일의 앞쪽 내용 일부를 출력하기 위한 것이나, 옵션을 조정하면 cat 명령처럼 내용 전체를 출력할 수 있다. 아래의 예시를 참고하자.

 

# myfile.txt에서 맨 앞 5개 행을 출력(-n 옵션값이 양수)

head -n 5 myfile.txt

 

# myfile.txt에서 맨 뒤 3개 행을 제외한 나머지를 출력(-n 옵션 값이 음수)

head -n -3 myfile.txt

 

# myfile.txt 내용 전체를 출력

head -n -0 myfile.txt

 

자, 이제 여러개의 파일에 대해 파일명과 함께 내용을 출력해 보자.

 

# .txt 파일에 대해 파일명과 내용 전체를 출력

head -n -0 *.txt

==> filename1.txt <==

[filename1.txt의 내용]

==> filename2.txt <==

[filename2.txt의 내용]

...

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2021. 7. 6. 17:32

 

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

 

정규표현(regular expression)을 이용하면 grep이나 sed에서 특정한 길이의 문자열에 대한 작업을 할 수 있다. 아래의 예시를 보자. my_file.txt 파일에서 영문 소문자로만 되고 길이가 5바이트(byte)인 행만 출력하는 경우이다.

 

cat my_file.txt | grep "^[a-z]\{5\}$"

 

중괄호({}) 안에 수자를 넣어서 바로 앞 표현이 얼만큼 반복되는지 지정할 수 있다. 중괄호가 shell에서 처리되는 것을 막고 grep 명령에 온전하게 인자로 전달되도록 역슬래시(\)로 보호해 준다. 중괄호를 이용한 반복 설정은 아래와 같다.

 

{n} 바로 앞의 항목이 정확히 n번 반복되는 경우

{n,} 최소 n번 이상 반복

{,m} 최대 m번 반복

{n,m} 최소 n번 이상, 최대 m번 반복

 

예시를 하나 더 보자. my_file.txt에서 영문 대소문자로 된 5바이트 이상 10바이트 이하 문자열이 있는 행만 출력하는 경우이다.

 

cat my_file.txt | grep "[[:alpha:]]\{5,10\}"

 

이 기능을 이용해서 2개 이상의 문자열이 동시에 포함된 행을 골라낼 수도 있다. 예를 들어 한 행에 abc와 def가 모두 있으면서 abc가 나온 후에 def가 나오는 문자열이 있는 부분을 찾는 경우이다. 아래의 예시를 보자.

 

cat my_file.txt | grep "abc[[:print:]]\{0,\}def"

 

위의 예시에서 grep 명령의 인자를 해석해 보자면, 문자열 abc 이후에 출력 가능한 문자([[:print:]])가 0번 이상(\{0,\}) 나온 후에 def가 나오는 경우를 찾아서 출력하라는 것이다.

 

2개 이상의 문자열이 동시에 포함된 행을 찾는 경우는 grep 명령을 파이프(|)로 연결하여 연속해서 사용할 수도 있다.

 

cat my_file.txt | grep "abc" | grep "def"

 

그러나, -v 옵션을 통해서 2개 이상의 문자열이 동시에 포함된 행을 제외하는 경우는 중괄호를 사용해야 한다.

 

# 검색한 문자열이 포함된 행을 제외(-v 옵션)

cat my_file.txt | grep -v "abc[[:print:]]\{0,\}def"

 

 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2021. 6. 28. 12:58

 

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

 

특정한 파일이 현재 전송되고 있는지 판단하기 위한 방법이다. 다수의 파일을 ftp로 받고 있거나 NFS를 통해서 복사하는 상황에서 이 파일들에 대한 작업을 해야 하는데, 전송중인 파일과 전송완료된 파일을 구분하기 위한 것.

파일이 마지막으로 수정된 시간과 현재 시간과의 차이를 확인하여 정해 둔 기준과 비교하면 되겠다. 파일이 마지막으로 수정된 시간은 stat 명령으로 확인한다. 아래의 예시를 보자.

# 마지막으로 수정된 시간, 1970.1.1 0시부터 경과한 시간을 초(second)로 표시

stat -c %Y my_file.txt

 

-c 옵션으로 출력할 항목을 지정하는데, %Y 항목을 사용. stat 명령을 이용하면 그 외에도 파일에 대한 다양한 정보를 확인할 수 있다. 자세한 내용은 man 페이지를 참고하자.

 

man stat

 

현재 시간은 date 명령을 사용하여 출력. 앞의 stat 명령과 동일한 형태로 출력할 수 있다.

 

# 현재 시간, 1970.1.1 0시부터 경과한 시간을 초(second)로 표시

date "+%s"

 

대상 파일이 현재 전송중이라면, 마지막으로 수정된 시간과 현재 시간과의 차이가 근소해야 한다. 별 문제가 없다면 1초 이하일 것이다. 만약 부하가 많이 걸리거나 네트워크 상태가 별로 좋지 않아서 전송이 지연되고 있다면 좀 더 차이가 날 수도 있을 것이다.

 

대강 시간차가 10초 이하면 현재 전송중이라고 판단하고 그 이상이라면 전송이 끝났다고 판단하는 경우의 예시를 보자.

 

# 대상 파일: my_file.txt

target_file=my_file.txt

# 시간차 기준: 10초

diff_limit=10

# 마지막으로 수정한 시간

mod_time=`stat -c %Y $target_file`

# 현재 시간

cur_time=`date "+%s"`

# 시간 차이 계산

diff=`echo "$cur_time - $mod_time" | bc`

# 시간차가 $diff_limit 이하면 전송중이라고 판단

if [ $diff -le $diff_limit ]

  then echo "$target_file: 전송중입니다."

  else echo "$target_file: 전송완료되었습니다."

fi

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2021. 6. 8. 14:20

 

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

 

특정 파일 또는 디렉토리가 존재하는지 확인하는 방법이다. 스크립트의 인자(argument)로 파일이나 디렉토리를 입력받았을 경우 인자의 유효성을 확인할 때 요긴하게 사용 가능.

우선 파일의 존재 여부를 확인해 보자. if 조건문에서 test 명령의 -e 옵션을 사용하면 된다. 아래의 예시를 참고하자.

 

file_name="my_file.txt"

# 파일이 있을 경우 메세지 출력

if test -e $file_name

then echo "$file_name 파일을 찾았습니다."

fi

 

# 파일이 없을 경우 메세지 출력(! 사용)

if ! test -e $file_name

then echo "$file_name 파일이 없습니다."

fi

 

디렉토리의 존재 여부는 -d 옵션을 사용하면 된다.

 

dir_name="/var/log/"

# 디렉토리가 있을 경우 메세지 출력

if test -d $dir_name

then echo "$dir_name 디렉토리를 찾았습니다."

fi

 

test 명령은 대괄호([ ])로 대체해서 쓸 수도 있다. 바로 위의 if 조건문 예시를 아래과 같이 써도 된다.

 

if [ -d $dir_name ]

then echo "$dir_name 디렉토리를 찾았습니다."

fi

 

대괄호를 사용할 때는 띄어쓰기에 주의하자. 대괄호 안의 표현과 대괄호 사이에 반드시 공백이 한칸 들어가야 한다.

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2021. 3. 3. 15:37

 

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

 

date 명령을 이용해서 파일을 마지막으로 수정한 날짜와 시간을 확인할 수 있다. -r 옵션을 사용한다. 아래의 예시를 보자.

 

date -r my_file.txt

2014. 07. 03. (목) 16:34:33 KST

 

원하는 항목만 골라내는 등 표시 형식을 바꿀 수도 있다. 아래의 예시를 보자.

 

# 연도만 구하기

date -r my_file.txt "+%Y"

2014

 

# 연도 및 날짜

date -r my_file.txt "+%Y%m%d"

20140703

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2021. 2. 19. 16:36

 

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

 

수 계산에 유용한 bc 명령을 이용하면 10진수를 2진수나 16진수로, 또는 그 반대로 변환할 수 있다. bc 명령에 대한 내용은 이전 게시물을 참고하자. 여기로 

 

일단 아래의 예시를 보자.

# 10진수를 2진수로 변환 (obase 변경)
echo "obase=2; 27" | bc
11011

bc에는 출력값과 입력값의 기수(base)를 설정하는 변수가 있는데, 각각 obase와 ibase이다. (기본적으로 10진수를 사용하므로 기본값은 둘 다 10이다.) obase 값을 2로 설정하면 출력값이 2진수로 표현된다. 반대로 2진수를 10진수로 변환하려면 ibase 값을 2로 설정하면 되겠다.

# 2진수를 10진수로 변환 (ibase 설정)
echo "ibase=2; 11011" | bc
27

# 2진수를 16진수로 변환
# obase 설정 이후 ibase 설정
echo "obase=16; ibase=2; 11011" | bc
1B

obase와 ibase를 둘 다 설정할 경우 obase 설정이 먼저 나와야 한다. 왜 그러냐 하면, 예를 들어 ibase를 먼저 2로 설정하면 그 다음에 obase를 설정할 때 입력할 값이 먼저 설정된 ibase 기준(즉 2진법)으로 되어야 하기 때문이다. 2진수를 16진수로 변환할 때 ibase를 먼저 설정하는 경우는 아래와 같이 좀 복잡해진다.

# 2진수를 16진수로 변환
# ibase 설정을 먼저 하는 경우
echo "ibase=2; obase=10000; 11011" | bc
1B

입력값의 기수를 정하는 ibase가 먼저 2진수로 설정되었기 때문에, obase를 16진수로 설정하려면 16을 2진수로 변환한 10000을 obase 값으로 설정해 주어야 한다. 복잡하다.

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2021. 2. 9. 14:02

 

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

 

연속적인 수를 생성해 주는 seq 명령에서 유용한 옵션들을 정리해 두기로.

일단 seq 명령에 대한 기본적인 내용은 이전 게시물을 참고하자. 여기로

 

아래의 예시들을 참고하자.

# 기본 명령: 2에서 4까지 생성하는 예시
seq 2 4
2
3
4

한줄에 하나씩 출력하지 않고 특정한 구분자(separator)를 사용하고 싶다면 -s 옵션을 이용하면 된다.

# 구분자를 콜론으로 변경: -s 옵션
seq -s ":" 2 5
2:3:4:5

 


구분자를 탭으로 변경하고 싶다면 echo 명령에서 -e 옵션을 사용.  따옴표에 유의하자. echo 부분을 역따옴표(`)로 감싼 후 이것을 다시 따옴표(")로 감싸주어야 한다.

# 구분자를 탭으로 변경
seq -s "`echo -e '\t'`" 2 5
2    3    4    5

 

출력값의 자리수를 맞추고 싶다면 -w 옵션을 사용하면 된다. 가장 긴 출력의 자리수에 맞춰서 앞에 0을 추가해 준다. 아래의 예시를 보자.

# 자리수 맞춤
seq -w 8 10
08
09
10

# 9에서 10까지 0.5 간격으로
seq -w 9 0.5 10
09.0
09.5
10.0

출력 형식을 정하고 싶다면 -f 옵션을 사용. -f 옵션과 -w 옵션은 같이 사용할 수 없으며 둘 중 하나만 사용해야 한다. -f 옵션에서는 C언어의 printf 형식을 사용할 수 있는데, 전부 다 쓸 수 있는 것은 아니고 %e, %f, %g 정도가 가능한 듯. 아래의 예시를 보자.

# %.2f: 소수점 아래 2자리까지 출력, 2부터 3까지 0.5 간격으로
# 정수부분만 출력하고 싶다면 %.0f 사용
seq -f "the number is %.2f" 2 0.5 3
the number is 2.00
the number is 2.50
the number is 3.00

# %e: 지수표현으로 출력, 200부터 300까지 50 간격으로
seq -f "the number is %.2e" 200 50 300
the number is 2.00e+02
the number is 2.50e+02
the number is 3.00e+02

# %g: 부동소수점(%f) 또는 지수표현(%e)중 출력값 길이가 짧은 쪽으로 선택해서 출력
seq -f "the number is %g" 2 0.5 3
the number is 2
the number is 2.5
the number is 3

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2021. 1. 28. 13:36

 

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

 

grep 명령을 이용하면 특정한 문자열을 포함하고 있는 파일들이 뭐가 있는지 찾을 수 있다. 훌륭하군!

일단 기본부터 차근차근 살펴보자. grep 명령의 기본 형식은 아래와 같다.

# [옵션]을 적용하여 [파일]의 내용을 검색, [문자열]을 찾음
grep [옵션] [문자열] [파일]

 

이제 아래의 예시를 보자. my_memo.txt 파일에서 abcd 문자열이 포함되어 있는지 검색하고 파일명과 함께 문자열이 포함된 행을 찾아 출력하는 것이다. -H 옵션을 주면 찾은 문자열뿐만 아니라 해당 파일명을 같이 출력해 준다. 파일명과 문자열은 콜론(:)으로 구분된다.

 

grep -H abcd my_memo.txt

my_memo.txt:abcdef

 

문자열은 필요 없고 파일명만 확인하고 싶다면 아래와 같이 -l 옵션을 추가하자.

 

grep -Hl abcd my_memo.txt

my_memo.txt

 

자, 이제 특정 디렉토리와 그 하위 디렉토리에 있는 여러개의 파일들 중에 특정한 문자열을 포함한 파일이 있는지 찾고 파일명을 확인해 보자. -r 옵션(recursive)을 이용하고 파일 대신 디렉토리를 지정하면 된다. 아래의 예시는 ~/Documents 디렉토리의 모든 파일을 검색, 내용에 abcd가 포함된 파일 찾아 파일명을 출력하는 경우이다.

 

grep -Hlr abcd ~/Documents

 

만약 특정 파일만 골라서 확인하고 싶다면 --include 옵션을 추가한다. 아래의 예시는 확장자가 txt인 파일만 대상으로 검색하는 경우이다.

 

grep -Hlr --include=*.txt abcd ~/Documents txt

 

파일 중에 v로 시작되는 파일은 제외하고 검색하려면 여기에 --exclude 옵션을 추가.

 

grep -Hlr --include=*.txt --exclude=v* abcd ~/Documents

 

 

Posted by 반달가면

댓글을 달아 주세요