bash script (backup)2020. 11. 24. 13:56

 

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

 

일단 my_file.txt에서 홀수번째 행만 골라서 출력하는 경우를 생각해 보자. 이 예시를 보면 짝수번째 행을 고른다던가 5, 10, 15... 번째 행만 고르는 경우도 저절로 감이 잡힐 것이다.

 

# my_file.txt의 홀수번째 행만 출력

print=p

max_line=`cat my_file.txt | wc -l`

for line_num in `seq 1 2 $max_line`

do

  sed -n $line_num$print my_file.txt

done

 

우선 my_file.txt에 행이 몇개나 되는지 계산해서 이 값을 변수 max_line에 할당하고, seq 명령을 이용해서 1부터 $max_line까지 홀수를 만든 후 for 반복문에 적용했다.

 

sed 명령을 이용해서 파일의 특정 행을 출력하는 방법은 아래와 같다.

 

sed -n [행번호]p [파일명]

 

# my_file.txt에서 12번째 행을 출력

sed -n 12p my_file.txt

 

여기서는 행번호가 변수 line_num이므로 여기에 p를 같이 쓰면 변수 line_nump로 해석된다. 이를 방지하기 위해 p를 변수 print에 할당하고 $line_num$print 이런 식으로 사용.

 

또한 -n 옵션을 주지 않으면 지정된 행을 출력한 후 파일 내용 전체를 출력하게 되므로 잊지 말고 -n 옵션을 써서 해당되는 행만 출력되도록 하자.

 

짝수행만 고르고 싶다면 for 명령에 적용한 seq 부분을 `seq 2 2 $max_line` 이런 식으로 바꾸면 되겠다. 출력하려는 행을 정하기 위해 이용한 seq 명령에 대한 설명은 이전 게시물을 참조하자. 기본적으로 형식은 아래와 같다. 

 

seq [시작번호] [간격] [끝번호]

참고로 파일의 특정 부분, 예를 들어 3번째 행부터 15번째 행까지를 골라내고 싶다면 아래와 같은 형식으로 사용하면 되겠다. 

 

# 형식: sed -n [시작행],[마지막행]p [파일명]

sed -n 3,15p my_file.txt

 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2020. 11. 16. 17:29

 

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

 

grep의 문자열 검색 기능을 매우 강력하지만 기본적으로 특정 문자열이 "포함된" 행을 찾아내는 것이다. 특정 문자열에 정확히 일치하는 항목이 있는지를 찾으려면 일이 약간 복잡해 진다.

 

일단 my_file.txt 파일의 내용이 아래와 같다고 생각해 보자.

 

john

john_smith

my name is john smith

my name is john_smith

 

일단 포함 여부가 아니라 행 전체가 일치하는 경우를 찾아야 한다면 -x 옵션으로 간단히 해결할 수 있겠다.

 

cat my_file.txt | grep -x "john"

john

 

또는 정규표현을 이용해도 된다. j로 시작되고(^j) 그 다음에 ohn이 있고 마지막에 n으로 끝나게(n$) 되는 문자열을 찾는 것이다.

 

cat my_file.txt | grep "^john$"

john

 

위 방법은 탭이나 공백이 포함되어 있을 경우에 문제가 될 수 있다. 예를 들어 my_file.txt의 john이라는 행이 john[공백] 이런 식이면 위의 방법으로는 검색이 안된다. 아니면 공백이 있다는 것을 미리 알고 grep의 인자에 반영해야 한다.

 

cat my_file.txt | grep -x "john "

 

탭이 포함된 경우라면 이런 식으로 반영하긴 어렵고 awk를 써야 한다. (탭이 포함된 문자열 검색은 이전 게시물을 참고하자.)

 

그렇다면 행 중간에 있는 특정 문자열을 정확하게 찾으려면 어떻게 할 것인가? 위의 my_file.txt에서 john_smith는 제외하고 john만 찾고 싶은 경우인데, grep의 정규표현과 이전에 게시했던 다중 문자열 검색 방법을 활용해 볼 수 있다.

 

정규표현 중에 [[:graph:]]라는 것이 있다. 화면에 표시할 수 있는 모든 문자(영문 대소문자 + 수자 + 특수기호)를 지칭한다. 공백은 제외된다. 공백도 포함하는 표현은 [[:print:]]이다.

 

자, 이제 아래의 예를 보자.

 

cat my_file.txt | grep "john" | grep -v "[[:graph:]]john\|john[[:graph:]]"

john

my name is john smith

 

우선 john이 포함된 행을 골라낸 후, john 앞에 다른 문자가 붙은 경우([[:graph:]]john) 또는(\|) john 뒤에 다른 문자가 붙은 경우(john[[:graph:]])를 -v 옵션으로 제외시킨 것이다.

 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2020. 11. 10. 17:48

 

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

 

조금 단순하긴 하지만, 리눅스 셸 스크립트에서도 일반 프로그래밍 언어에서처럼 함수(function)를 만들어서 사용할 수 있다.

일단 형식은 아래와 같다.

function [함수 이름](){
...
return
}

함수를 호출할 때는 그냥 함수 이름을 쓰면 된다. 아래의 예시를 보자. 수자 2개를 인자로 받아서 앞의 수와 뒤의 수를 더한 후 이 값을 제곱하는 계산을 하는 함수를 만들어 보면 대략 아래와 같다. 함수 이름은 arith_test이고 스크립트 안에서 arith_test 3 4 이런 식으로 호출해서 쓰면 된다. bc 명령을 이용한 산수 계산은 이전 게시물을 참고하자.

# 함수 arith_test: f = (x+y)^2
function arith_test(){
  echo "( $1 + $2 )^2 | bc"
  return
}

# main
# 함수 호출. (4+5)^2 계산후 결과를 화면에 출력
arith_test 4 5
# 함수 호출. (3+4)^2 계산후 결과를 result 변수에 할당
result=`arith_test 3 4`

함수에서 계산한 결과를 변수에 할당할 경우, 가장 처음 echo 명령으로 출력된 결과가 변수에 할당된다. 위의 예시에는 echo 명령이 하나뿐이므로 상관 없다. 결과를 변수에 할당하는 방식을 쓰고 싶다면, 함수 안에 echo 명령은 하나만 있는 것이 좋겠다.

스크립트에서 사용하는 변수는 기본적으로 전역변수(global variable)이다. 만약 함수 안에서만 의미가 있는 지역변수(local variable)를 사용하고 싶다면 함수 안에서 변수이름 앞에 local을 붙이면 되겠다. 아래의 예를 보자.

function var_test(){
  local test_var_local="LOCAL"
  test_var_global="GLOBAL"
  return
}

# main
# 함수 호출
var_test
# 변수값 확인. test_var_local 값은 출력되지 않음(지역변수)
echo "$test_var_local"
echo "$test_var_global"

함수 기능은 때에 따라 아주 요긴하게 쓸 수 있다!


 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2020. 11. 9. 17:11

 

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

 

grep을 이용한 문자열 검색에서 정규표현(regular expression)은 매우 유용하지만 이걸 비활성화해야 될 경우가 있다. 일단, 찾고자 하는 문자열이 명시적으로 정해져 있다면 문제는 간단하다. 문자열을 작은따옴표로 감싸거나, 정규표현에 사용되는 [, -, ] 등의 기호 앞에 역슬래시(\) 기호를 사용하면 된다. 아래의 예시를 보자.

 

# a부터 z까지, 즉 영소문자를 검색하는 정규표현

cat my_file.txt | grep "[a-z]"

 

# 검색하려는 문자열 자체가 '[a-z]'인 경우

cat my_file.txt | grep '[a-z]'

cat my_file.txt | grep "\[a\-z\]"

 

그러나 만약 변수에 할당된 문자열에 정규표현에 사용되는 기호가 포함되어 있을 경우엔 어떻게 할 것인가? 이 경우엔 정규표현으로 해석이 되지 않도록 -F 옵션을 사용하면 된다.

 

str="[a-z]"

cat my_file.txt | grep -F "$str"

 

이렇게 해도 해결이 안되는 경우가 있는데, 검색하고자 하는 문자열이 하이픈(-)으로 시작되는 경우이다. 이 경우에는 -e 옵션을 같이 사용하자.

 

str="-[a-z]"

cat my_file.txt | grep -Fe "$str"

 

파일에서 문자열을 읽어서 변수에 할당하고 이 변수가 grep 명령어에 사용되는 경우, 문자열에 특수문자들이 포함될 가능성이 있다면 -Fe 옵션을 추가해 주자.

 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2020. 11. 5. 13:20

 

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

 

스크립트로 반복작업을 해야 하는데, A 작업을 일단 완료하고 나서 시간이 X초 이상 흘렀으면 B 작업을 하고 아직 안 지났으면 C 작업을 해야 하는 좀 애매한 상황이 있어서 이걸 처리하려고 생각한 방법이다.

date 명령에서 출력 형식에 %s 옵션을 사용하면 UTC 기준 1970년 1월 1일 00시 00분 00초부터 몇초가 흘렀는지를 표시해 주는데, 이것을 이용했다. 아래의 예시 스크립트를 참고하자.

# 예시: A작업후 10초 이상 흘렀으면 B작업 실행, 아니면 C 작업 실행
start_time=`date "+%s"`
echo "A작업을 수행합니다!"
# A작업 수행
...
stop_time=`date "+%s"`
# 경과한 시간 = 종료시간 - 시작시간
interval=`echo "$stop_time - $start_time" | bc`
if test $interval -ge 10
then echo "10초 이상 경과. B작업을 수행합니다!"
# B작업 수행
...
else echo "아직 10초 안 됐음. C작업을 수행합니다!"
# C작업 수행
...
fi

 

나노초(nanosecond)를 표시하는 %N 옵션을 이용하면 간단한 스톱워치도 구현 가능. 아래의 예시를 참고하자.

#stopwatch.sh
echo "press ENTER to start"
read enter
start_time=`date "+%s.%N"`
echo "press ENTER to stop"
read enter
stop_time=`date "+%s.%N"`
result=`echo "$stop_time - $start_time" | bc`
echo "$result sec"

 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2020. 11. 3. 16:53

 

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

 

작성한 셸 스크립트의 동작이 뭔가 이상할 때, 어느 부분에 문제가 있는지 찾기 위해 -x 옵션을 활용할 수 있다.

 

작성한 스크립트가 my_script.sh라고 하면, 아래와 같이 실행해 보자.

 

bash -x my_script.sh

 

스크립트가 실행되면서 명령어와 각 변수에 할당된 값들이 화면에 출력된다. 스크립트 실행 중간에 오류가 나서 종료되는 상황이라면 오류가 발생하기 직전까지의 실행 결과를 볼 수 있다.

 

개인적으로는 이 출력 내용을 다른 파일로 저장한 후 차근차근 살펴보는 식으로 사용하는데, 좀 길고 복잡한 스크립트를 만들어야 할 경우에 꽤 도움이 된다. 출력 결과를 my_script.log 파일에 저장하려면 아래의 예를 참고하자.

 

bash -x my_script.sh > my_script.log

 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2020. 11. 3. 16:49

 

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

 

그냥 예제를 하나 적어두는 것이 가장 나을 것 같다.

 

예를 들어 people.txt 파일의 내용이 아래와 같이 이름::이메일::나이 형태라고 해 보자.

 

john::john@mail.com::24

mary::mary@mail.com::22

 

이것을 이메일[탭]이름[탭]나이 형태로 바꿔서 result.txt 파일에 저장하려고 한다. 아래와 같이 하면 되겠다.

 

cat people.txt | awk -v FS="::" -v OFS="\t" '{ print $2,$1,$3 }' > result.txt

 

-v 옵션으로 awk의 내부 변수를 설정해 주는데, FS는 입력에 적용하는 항목 구분자(field separator)이고 OFS는 출력에 적용하는 항목 구분자이다.

 

FS에 지정된 구분자를 기준으로 첫번째 항목은 $1에, 두번째 항목은 $2에 대응된다. 위의 예시를 기준으로 보면 $1은 이름, $2는 이메일에 대응될 것이다.

 

이름과 이메일의 순서를 바꿔야 하므로 print 명령에서 순서를 $2,$1,$3 이렇게 했다. 그리고 이 결과를 result.txt로 저장.

 

result.txt의 내용은 아래와 같이 될 것이다.

 

john@mail.com john 24 mary@mail.com mary 22

 

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2020. 10. 28. 13:22

 

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

 

특정 범위의 수자를 차례로 만들어야 할 때는 seq 명령을 쓰면 되겠다. 형식은 아래와 같다.

seq [시작번호] [끝번호]

seq [시작번호] [간격] [끝번호]

아래의 예시를 보자.

# 3부터 7까지 순서대로 출력
seq 3 7
3
4
5
6
7

# 3부터 10까지 2 간격으로 출력
seq 3 2 10
3
5
7
9

for 명령을 이용한 반복작업에도 활용할 수 있다.

start_num=3
end_num=10
interval=2
for i in `seq $start_num $interval $end_num`
do
echo "the number is $i"
done

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2020. 10. 26. 11:47

 

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

 

sed를 이용해서 특정 문자열을 다른 문자열로 바꾸는 방법이다. 일단 아래의 예시를 보자.

 

# 처음 나오는 abc를 ABCD로 교체

echo "abc_abc_abc" | sed "s/abc/ABCD/"
ABCD_abc_abc

 

g 옵션을 추가하면 지정한 모든 문자열을 바꾼다.

 

# 모든 abc를 ABCD로 교체

echo "abc_abc_abc" | sed "s/abc/ABCD/g"
ABCD_ABCD_ABCD

 

grep에서 주로 사용하는 정규표현(regular expression)도 사용할 수 있다.

 

# abc로 끝나는 부분을 ABCD로 교체
echo "abc_abc_abc" | sed "s/abc$/ABCD/"
abc_abc_ABCD

 

파일에서 문자열을 바꾸고 다른 파일로 저장하려면 아래와 같이 하면 되겠다.

 

sed "s/abc/ABCD/" my_file.txt > my_file_modified.txt

 

또는

 

cat my_file.txt | sed "s/abc/ABCD/" > my_file_modified.txt

 

특정 문자열을 없앨 수도 있다. 아래의 예시를 참고하자.

 

# 처음 나오는 abc를 제거

echo "abc_abc_abc" | sed "s/abc//"

_abc_abc

 

Posted by 반달가면

댓글을 달아 주세요

bash script (backup)2020. 10. 23. 14:38

 

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

 

텍스트 파일의 각 행을 무작위로 뒤섞거나 특정 범위의 수를 무작위로 뒤섞고 싶을 때는 shuf 명령을 사용하면 되겠다.

 

예를 들어 my_file.txt에서 무작위로 5개의 행을 뽑아서 화면에 출력하고 싶다면 아래와 같이 하면 되겠다.

 

shuf -n 5 my_file.txt

 

my_file.txt의 전체 행을 무작위로 재배열하고 싶다면, my_file.txt가 몇개의 행으로 이루어져 있는지 찾은 후 이 값을 -n 옵션에 넘겨주자.

 

shuf -n `cat my_file.txt | wc -l` my_file.txt

 

출력 결과를 다른 파일로 저장하고 싶다면 redirection을 이용하면 된다.

 

shuf -n `cat my_file.txt | wc -l` my_file.txt > my_file_shuffled.txt

 

만약 35이상 45이하의 수를 무작위 순서로 출력하고 싶다면 아래과 같이 -i 옵션을 사용하면 된다.

 

shuf -i 35-45

 

사무실에서 커피 내기 사다리 타기 대신으로도 활용할 수 있을 듯;;

 

 

Posted by 반달가면

댓글을 달아 주세요