검색 엔진의 방문이 늘어나고 있군...

Posted
Filed under 쉘 스크립트
인터넷을 검색하며 백업을 위한 배치 파일을 만들어 봤습니다. 핵심 내용은 실행할 때마다 30일 이전의 백업본을 지우는 것입니다. 윈도우 스케줄러를 통해 새벽에 돌리면 간단한 백업에 사용할 수 있을 것 같습니다. 에코는 일부로 꺼놓지 않았으므로 명령어가 거슬릴 경우 @echo off 를 첫 번째 줄로 추가하면 됩니다.
set date2=%date:-=%
set YEAR=%date2:~0,4%
set MONTH=%date2:~4,2%
set DAY=%date2:~6,2%
set CurDate=%YEAR%%MONTH%%DAY%
set dayCnt=30

xcopy "C:\Backup" "D:\BACKUP_%CurDate%\" /D /F

REM Substract your days here
set /A DAY=1%DAY% - 100 - %dayCnt%
set /A MONTH=1%MONTH% - 100

:CHKDAY

if /I %DAY% GTR 0 goto DONE

set /A MONTH=%MONTH% - 1

if /I %MONTH% GTR 0 goto ADJUSTDAY

set /A MONTH=12
set /A YEAR=%YEAR% - 1

:ADJUSTDAY

if %MONTH%==1 goto SET31
if %MONTH%==2 goto LEAPCHK
if %MONTH%==3 goto SET31
if %MONTH%==4 goto SET30
if %MONTH%==5 goto SET31
if %MONTH%==6 goto SET30
if %MONTH%==7 goto SET31
if %MONTH%==8 goto SET31
if %MONTH%==9 goto SET30
if %MONTH%==10 goto SET31
if %MONTH%==11 goto SET30
REM ** Month 12 falls through

:SET31

set /A DAY=31 + %DAY%

goto CHKDAY

:SET30

set /A DAY=30 + %DAY%

goto CHKDAY

:LEAPCHK

set /A tt=%YEAR% %% 4

if not %tt%==0 goto SET28

set /A tt=%YEAR% %% 100

if not %tt%==0 goto SET29

set /A tt=%YEAR% %% 400

if %tt%==0 goto SET29

:SET28

set /A DAY=28 + %DAY%

goto CHKDAY

:SET29

set /A DAY=29 + %DAY%

goto CHKDAY

:DONE

if /I %MONTH% LSS 10 set MONTH=0%MONTH%
if /I %DAY% LSS 10 set DAY=0%DAY%

echo Date %dayCnt% day(s) before %CurDate% is %YEAR%%MONTH%%DAY%
rmdir /S /Q "D:\BACKUP_%YEAR%%MONTH%%DAY%\"



2014/12/01 19:29 2014/12/01 19:29
Posted
Filed under 쉘 스크립트
참조 원문 : Unix: Tracking disk space usage

  특정 파일에 날짜와 df의 결과 중 사용률을 기록하는 스크립트로서 사실 스크립트의 결과물이 뛰어나거나 한 건 아닌데 처리 방법이 독특한 것 같아 기록합니다.

  먼저 스크립트를 작성한 곳의 파일시스템 상태는 아래와 같습니다.
$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
                       34G   28G  4.7G  86% /
/dev/sda1              99M   16M   79M  17% /boot
/dev/sda2            11.0G  9.8G  1.2G  89% /home
tmpfs                 7.9G  200M  7.7G   3% /dev/shm
  첫 번째 파일시스템명이 너무 길어 두 줄로 나눠서 출력된 걸 볼 수 있습니다. 아래는 이를 염두하고 작성한 스크립트 내용입니다.
#!/bin/bash

dt=`date +%D`
log="/var/tmp/du.log"

df -h > /tmp/du$$

while read line
do
    fields=`echo $line | awk '{print NF}'`
    case $fields in
    1) echo -n "$dt $line " >> $log;;
    5) echo $line | awk '{print $4}' >> $log;;
    6) echo -n "$dt "
        echo $line | awk '{print $1,$5}' >> $log;;
    esac
done < /tmp/du$$

rm /tmp/du$$
  기록되는 내용은 아래와 같습니다.
09/15/13 /dev/mapper/VolGroup00-LogVol00 86%
09/15/13 /dev/sda1 17%
09/15/13 /dev/sda2 89%
09/15/13 tmpfs 3%
  원한다면 파일시스템명 대신 마운트 포인트를 기록할 수 있습니다. 이 경우 파일시스템명이 너무 길어서 두 줄로 나뉜 상황일 때 파일시스템명만 나온 줄은 무시하게 됩니다. 다만 정상적인 줄과는 필드의 개수가 다르므로 여전히 별도의 처리는 필요합니다.
#!/bin/bash

dt=`date +%D`
log="/var/tmp/du.log"

df -h > /tmp/du$$

while read line
do
    fields=`echo $line | awk '{print NF}'`
    case $fields in
    5) echo -n "$dt " >> $log
        echo $line | awk '{print $5,$4}' >> $log;;
    6) echo -n "$dt " >> $log
        echo $line | awk '{print $6,$5}' >> $log;;
    esac
done < /tmp/du$$

rm /tmp/du$$
  기록되는 내용은 아래와 같습니다.
09/15/13 / 86%
09/15/13 /boot 17%
09/15/13 /home 89%
09/15/13 /dev/shm 3%
2013/09/20 06:44 2013/09/20 06:44
Posted
Filed under 쉘 스크립트
참조 원문 : Unix tip: Using Bash's regular expressions

  버전 3(2004년)부터 bash는 =~ 로 표기하는 내장형 정규 표현식 비교 연산자를 갖추었습니다. 그래서 사실 스크립트에서 grep이나 sed로 하는 작업의 상당수는 이 연산자로 처리할 수 있습니다.

  다른 비교 연산자(-lt, == 등)와 마찬가지로 비교 결과가 참이면 0을 리턴합니다. 아래 예제는 $digit의 값이 하나의 숫자인지를 판별하는 것을 보여주고 있습니다.
if [[ $digit =~ [0-9] ]]; then
    echo '$digit is a digit'
else
    echo "oops"
fi

  아래는 프롬프트에 입력한 값이 숫자만으로 구성되어 있는지를 판별하는 예제입니다.
echo -n "Your answer> "
read REPLY
if [[ $REPLY =~ ^[0-9]+$ ]]; then
    echo Numeric
else
    echo Non-numeric
fi

  Bash의 정규 표현식도 상당히 복잡하게 응용해서 사용할 수 있습니다. $email 변수의 값이 이메일 주소 형식인지를 판별하는 예제입니다. 첫 번째 표현식(계정명)은 문자, 숫자, 일부 특수 문자를 받습니다. 첫 번째 ]의 오른쪽에 있는 +는 앞의 표현식에 해당하는 문자를 몇 개든지 받는다는 뜻입니다. 그 뒤에는 계정명과 이메일 도메인 사이에 @ 문자가 있는지 확인합니다. 그리고 도메인 명의 앞부분과 뒷부분 사이에 점(\.)이 있는지 확인합니다.
if [[ "$email" =~ "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$" ]]
then
    echo "This email address looks fine: $email"
else
    echo "This email address is flawed: $email"
fi

  아래는 변수의 값이 IP 주소 형태인지를 판별하는 예제입니다.
#!/bin/bash

if [ $# != 1 ]; then
    echo "Usage: $0 address"
    exit 1
else
    ip=$1
fi

if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
    echo "Looks like an IPv4 IP address"
elif [[ $ip =~ ^[A-Fa-f0-9:]+$ ]]; then
    echo "Could be an IPv6 IP address"
else
    echo "oops"
fi

  또한 bash는 간소화된 루프문을 제공합니다. 100번 루프하고 싶다면 아래의 문법으로 해결할 수 있습니다.
for n in {1..100}
do
    echo $n
done

  아래와 같은 표현식으로 문자나 숫자를 범위로 지정하여 루프를 처리할 수도 있습니다. 꼭 1이나 a부터 시작할 필요는 없으며, 역순으로 처리하는 것도 가능합니다.
{a..z}
{z..a}
{c..f}
{5..25}
{10..-10}

  쉘에서 아래처럼 간단히 확인해볼 수도 있습니다.
$ echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
$ echo {5..-1}
5 4 3 2 1 0 -1
2013/07/15 12:42 2013/07/15 12:42
Posted
Filed under 쉘 스크립트
참조 원문 : Ten things I wish I knew earlier about the Linux command line

1. Ctrl+U와 Ctrl+Y(bash 한정)
  긴 명령어를 치던 도중 다른 명령어를 먼저 실행해야 하는 상황을 겪어본 적이 있는가? 이럴 때 좋은 방법이 있다. 커서가 현재 명령줄의 끝에 오게 한 후(단축키: Ctrl+E) Ctrl+U를 누르면 줄이 비워진다. 먼저 실행해야 할 다른 명령어를 실행한 후 Ctrl+Y를 누르면 아까 쳤던 명령어가 그대로 붙여진다.

2. screen 명령어
  하나의 터미널 세션 속에서 다수의 터미널 세션을 실행하는 명령어다. 세션은 단축키로 관리한다. 기본으로 설치되지 않을 수 있으니 필요하다면 설치해야 한다. 실행하면 도움말 같은 것이 나온 후 빈 터미널 창이 나온다. 여기서 sleep 9999를 실행해서 터미널을 일시적으로 사용하지 못하는 상태로 만들자. 그리고 나서 Ctrl+A를 누른 후 c를 누르면 새로운 창이 열린다. sleep 명령어를 실행하던 터미널은 계속해서 작동하고 있다. 두 창 사이를 옮겨 다니는 단축키는 Ctrl+A n(Next)와 Ctrl+A p(Previous)다. 명령어를 실행 중인 상태에서 실행에 중단 없이 screen을 종료하려면 Ctrl+A d(Detach)를 누른다. 이렇게 종료했던 screen 터미널로 돌아가려면 screen -R을 실행한다.

3. xargs 명령어
  다수의 파일이나 어떤 파일의 여러 줄을 참고하여 명령어를 실행할 때 xargs는 큰 도움이 된다. 원래 시스템이 처리할 수 있는 커맨드 라인 인자의 양과 크기에는 한계가 있지만 xargs를 사용하면 모든 인자를 다 처리하면서도 명령어 사용 횟수는 최소화한다. 아래는 사용 예다.
find . -iname '*.php' -print0 | xargs -0 svn add
  svn 같은 버전 제어 시스템을 다뤄 본 사람이라면 코드 파일을 새로 만들 때마다 귀찮게 svn add를 해줘야 한다는 것을 알것이다. 위 명령어는 이 일을 한 번에 해결한다. 원리는 아래와 같다.
  1. "find . -iname '*.php' -print0"로 현재 디렉토리(".") 이하에 있으면서 파일명이 .php로 끝나는(대소문자 미구분) 파일명을 출력하고 이때 각 출력 사이를 널 문자("-print0")로 구분한다. 널 문자는 파일명에 절대 사용되지 않지만 줄 바꿈 문자는 사용될 수 있기 때문에 널 문자로 나누는 것이 더 안전하다.
  2. "xargs -0 svn add"는 파이프("|")를 통해 표준 입력으로 앞선 명령어의 출력을 받아 널 문자("-0")로 나눠진 각 인자를 인식하고 svn의 "add" 인자 뒤에 파일명을 인자로 넣는다.
  find에서 -exec 옵션을 쓰는 것과 비교했을 때 xargs를 사용하는 것이 더 안전하고 활용성도 높다.

4. bash를 간단한 계산기로 사용
echo $((3*37+12)) # 출력 123
echo $((2**16-1)) # 2의 16제곱 빼기 1; 출력 65535
echo $((103/10)) # 출력 10, 모든 연산은 정수로 처리한다.
echo $((103%10)) # 출력 3, 103을 10으로 나눴을 때의 나머지
  비트 연산도 지원하며 캐럿("^")으로 할 수 있는데 그래서 일반적인 계산기 프로그램과 달리 "^"가 아닌 "**"가 제곱을 위한 문자로 쓰인다. 아래처럼 16진수나 8진수를 10진수로 변환할 수도 있다.
echo $((0xdeadbeef)) # 출력 3735928559
echo $((0127)) # 출력 87
  더 자세한 것은 man bash에서 "arithmetic evaluation"을 검색하면 볼 수 있다. 계산에 소수점을 사용하고 싶다면 아래처럼 bc를 사용하는 것이 좋다.
echo 'scale=12; 2.5*2.5' | bc # 출력 6.25
echo 'scale=12; sqrt(14)' | bc # 출력 3.741657386773
  bc를 사용할 때 당신이 원하는 정확도로 소수점 연산을 할 수 있다. scale 변수는 소수점 이하의 자릿수를 제어한다.

5. 작은 따옴표
  작은 따옴표는 그 안에 있는 문자를 쉘이 해석하지 않고 그대로 명령어에 넘기는 역할을 한다.
find . -iname '*.conf'
  *.conf를 둘러싸고 있는 작은 따옴표를 보자. 만약 이걸 빼면 bash는 *.conf를 glob expression으로 해석하여 현재 디렉토리에서 파일명이 .conf로 끝나는 모든 파일로 대체하기 때문에 서브 디렉토리는 검색하지 않는다는 결과를 초래한다. 그러므로 특수 문자를 포함한 것에는 항상 작은 따옴표를 붙이는 것이 좋다.

6. For 루프문
  xargs를 사용하면 다수의 파일에 한 명령어에 실행할 수 있다. 하지만 경우에 따라 그보다 더 강력한 기능이 필요할 때가 있다. 예를 들어 아래를 보자.
# 현재 디렉토리에 있는 각 php 파일에 while 루프문이 몇 개 있는지 조사
for file in ./*.php; do echo -n "$file":\ ; grep 'while' "$file" | wc -l; done
  1. "for file in ./*.php": 현재 디렉토리에서 파일명이 ".php"로 끝나는 모든 파일의 목록을 만들고 각 파일마다 그 이름을 "$file"이라는 변수에 넣고 아래의 코드들을 실행한다.
  2. "do ... done": 루프문 안에 있는 코드의 시작과 끝을 나타낸다. 원래는 둘 다 줄의 시작에 있어야 하며 그것이 각각의 앞에 세미콜론이 있는 이유다.
  3. "echo -n "$file":\ ": 파일명, 콜론, 공백 문자를 출력하며 줄을 바꾸지 않는다.("-n" 옵션을 사용하면 줄을 바꾸지 않는다.) 백슬래쉬는 공백 문자 1개를 bash가 먹지 않고 그대로 출력하기 위해 사용했다.
  4. "grep 'while' "$file" | wc -l": 파일을 읽어 "while"이라는 문자열이 있는 줄만 파이프를 통해 "wc -l" 명령어로 보내 총 몇 줄인지 센다.

7. 문자열 조작
  파일명이 DSC로 시작하는 다수의 사진 파일이 있다고 가정하자. 이 DSC를 Vacation2011로 바꾸는 방법은 아래와 같다.
for file in DSC*; do mv "$file" Vacation2011"${file#DSC}"; done
  여기서 중요한 부분은 "${file#DSC}"이다. #은 그 뒤에 있는 문자열을 그 앞에 있는 변수의 내용의 앞부분에서 지워야 한다는 것을 뜻한다. 문자열의 뒤에서 지우는 연산자도 있다.(파일 확장자를 없앨 때 유용하다.) 문자열을 찾아 치환하는 것에 대한 자세한 것은 이곳을 참조하자.

8. 프로세스 대체(Process Substitution)
  두 명령어의 출력 결과에서 차이점을 빠르게 찾고 싶은가? 물론 아래처럼 두 결과를 임시 파일로 리다이렉트해서 비교하는 방법도 있다.
find /etc | sort > local_etc_files
find /mnt/remote/etc | sort > remote_etc_files
diff local_etc_files remote_etc_files
rm local_etc_files remote_etc_files
  위 작업을 통해 로컬 컴퓨터와 원격 컴퓨터의 /etc 디렉토리가 각각 어떤 파일을 가지고 있는지 비교할 수 있다. 하지만 4줄이나 소모했다. 프로세스 대체를 사용하면 한 줄로 할 수 있다.
diff <(find /etc | sort) <(find /mnt/remote/etc | sort)
  <(...) 문법은 "안에 있는 명령어를 실행하고 출력을 임시 파이프 파일에 연결시킨 후 그것을 인자로서 사용하라"는 뜻을 담고 있다. 좀 더 완벽한 이해를 위해 아래를 실행해보자.
echo <(echo test)
  "test"라는 문자열을 출력하는 대신 "/dev/fd/63" 같은 문자열을 출력할 것이다. 이것을 통해 <(...) 부분이 파일로 교체된다는 것을 알 수 있다. 이 파일은 <(...) 안에 있는 명령어의 출력으로 인한 스트림으로서 아래처럼 읽는 것이 가능하다.
cat <(echo test)
  Bash는 "echo test"의 출력을 /dev/fd/<파일디스크립션번호>로 리다이렉트하고 그 파일의 경로명을 cat에게 넘기며, cat은 그 파일로부터 echo의 출력을 읽는다. 이 기술은 임시 파일이 필요할 때 쓸 수 있지만 제한사항이 있다. 이 임시 파일은 사라지기 전에 한 번만 읽을 수 있다. 임시 파일의 이름을 보관했다가 나중에 사용하는 것은 불가능하다는 것이다. 프로그램의 출력을 여러 번 참조해야 한다면 그냥 임시 파일을 만들거나 파이프를 써야 한다.


2013/07/04 11:29 2013/07/04 11:29
Posted
Filed under 쉘 스크립트
참조 원문 : 7 hidden features of bash

1. 이전 명령어 다시 실행
  sudo를 사용 안 하고 root 권한이 필요한 명령어를 했을 때 아주 유용한 기능. 파라미터로 !! 를 입력하면 마지막으로 실행했던 명령어를 반복한다. 예를 들어 apt-get 명령어를 사용했는데 sudo를 쓰지 않아서 앞에 sudo를 붙여 다시 실행해야 하다면 sudo !! 라고 실행한다.

2. bash 스크립트
bash -n bashscript.sh  ->  실제로 스크립트를 실행하지 않고 문법만 검사.
bash -x bashscript.sh  ->  디버그 모드로 스크립트 실행. 각 명령어와 그 결과를 단축하여 출력.

3. 이전 명령어의 특정 문자열을 치환
  ^이전문자열^새문자열^ 문법으로 달성할 수 있다.
$ sudo apt-get install wrongpackagename
$ ^wrongpackagename^rightpackagename^
sudo apt-get install rightpackagename
  sed나 vi와 비슷한 다른 방법도 있다.
$ sudo apt-get install wrongpackagename
$ !!:s/wrongpackagename/rightpackagename
sudo apt-get install rightpackagename

4. 이전 줄의 마지막 파라미터 사용
  가끔 명령어에서 긴 파라미터를 썼는데 그걸 또 써야 할 때가 있다. 예를 들어 어떤 디렉토리를 만들고 그 디렉토리로 이동하려고 할 때 아래와 같은 방법으로 이동할 수 있다.
# mkdir -p /this/is/mylong/pathto/some/directory
# cd $_
  $_는 마지막에 사용했던 명령어의 마지막 파라미터를 뜻한다. 그 이전 명령어들의 마지막 파라미터를 사용하고 싶다면 'Alt + .' 단축키를 사용하면 된다. 이 단축키를 사용하면 마지막 파라미터를 출력하며, 한 번 더 누를 때마다 그 이전 명령어의 마지막 파라미터를 출력한다.

5. 지금 있는 디렉토리에서 하위 디렉토리만 출력
ls -d */
  -d 옵션은 디렉토리 엔트리만 보여주는 옵션이지만 파라미터를 입력하지 않으면 현재 디렉토리를 파라미터로 사용하기 때문에 '.'만 나온다.

6. 예전 명령어 검색
  'Ctrl + r'을 누르면 예전에 사용한 명령어를 검색할 수 있다. Ctrl + r을 누르고 타이핑을 치면 입력한 모든 텍스트를 포함하고 있는 명령어들 중 가장 최근에 사용한 것을 보여주며 Ctrl + r을 누를 때마다 더 오래된 명령어를 보여준다. 만약 지나쳤다면 Ctrl + s를 눌러 앞으로 검색하면 된다.

  하지만 Ctrl + s는 일반적으로 XOFF(interrupt data flow)로 맵핑되어 있는데 현대에는 거의 필요가 없는 기능이므로 stty -ixon 명령어를 통해 맵핑을 끊으면 된다.

7. 길고 복잡고 어려운 명령어를 입력하기 위해 기본 편집기($EDITOR 환경 변수에 설정된 에디터) 즉시 소환
  명령어를 쓰다가 Ctrl + x + e를 누르면 편집기가 실행되면서 쓰던 명령어가 그곳에 적힌다. 편집기에서 명령어를 완성하고 저장 후 종료하면 작성했던 내용이 쉘에서 실행된다.



2013/07/03 16:51 2013/07/03 16:51
Posted
Filed under 쉘 스크립트

참조 원문1 : SED(Stream EDitor ) Explained in detail for Linux/Unix
참조 원문2 : Learn SED with examples

1. 검색과 치환(s는 search의 약자)
  아래는 단어를 찾아 다른 단어로 치환하는 문법이다.
sed 's/searchterm/replaceterm/' inputfile
또는
cat inputfilename | sed 's/searchterm/replaceterm/'
또는
echo "This is test message" | sed 's/searchterm/replaceterm/'

예제1: test.txt 파일에서 google을 찾아 yahoo로 치환
sed 's/google/yahoo/' test.txt

예제2: sed는 기본적으로 처음 찾은 단어만 치환한다. 모든 단어를 치환하려면 g 스위치를 사용해야 한다.
echo "sheena leads, sheila needs" | sed 's/sh/le/g'

예제3: Separator 변경법. Separator가 검색하려는 단어에 포함된 경우 유용하다. 예를 들어 /var/ftp/pub을 검색하여 /opt/ftp/com으로 치환하려고 할 때 아래처럼 해도 제대로 작동하지 않는다.
sed 's//var/ftp/pub//opt/ftp/com/' test.txt
이럴 땐 separator를 /에서 #나 $ 같은 다른 문자로 바꿔야 한다. 아래는 _를 사용하는 예제다.
sed 's_/var/ftp/pup_/opt/ftp/com_' test.txt

예제4: 아래는 surendra를 Mr. surendra로 바꾸는 예제다.
sed 's/surendra/Mr. &/' test.txt

예제5: 아래는 abc123suri 같은 패턴을 suriabc123으로 바꾸는 예제다.
echo "abc123suri" | sed 's/([a-z]*)([0-9]*)([a-z]*)/312/'


2. 출력(-n과 p 스위치)
예제6: 기본적으로 sed는 모든 줄을 출력하지만 -n(출력 억제)과 p 옵션을 사용하여 바뀐 줄만 출력할 수 있다.
cat tem.txt | sed -n 's/surendra/bca/p'


3. 수정(-i, w, d 스위치와 쉘 리다이렉션)
예제7: -i 옵션을 사용하면 변경점을 원본 파일에 적용할 수 있다.
sed –i 's/bca/Surendra/' tem.txt

예제8: 리다이렉션으로도 같은 일을 할 수 있다.
sed 's/baby/dady/' < tem.txt > abc.txt

예제9: w 옵션으로 변경점을 다른 파일에 저장할 수 있다.
sed 's/baby/dady/w abc.txt' tem.txt


4. 여러 SED 명령어와 연속 연산자(-e와 ; 스위치)
예제10: Surendra, mouni, baby를 bca, mca, bba로 치환
sed -e 's/surendra/bca/' -e 's/mouni/mca/' -e 's/baby/bba/' tem.txt

예제11: ;(연속 연산자)로 더 위보다 더 줄이기
sed 's/Surendra/bca/;s/mouni/mca/;s/baby/bba/' tem.txt


5. 줄 번호 연산자(,와 = 스위치)
예제12: 3번째 줄 내용만 검색해서 치환하기
sed '3 s/Surendra/bca/' tem.txt

예제13: 1~4번째 줄 내용만 검색해서 치환하기
sed '1,4 s/Surendra/bca/' tem.txt

예제14: 2번째 줄에서부터 문서 끝까지 검색해서 치환하기
sed '2,$ s/Surendra/bca/' tem.txt

예제15: 매 두 줄마다 한 줄로 결합. 아래는 N 옵션으로 두 줄을 합치는 예제. 치환으로 \n을 공백 같은 것으로 바꿔줘야 원하는 의도대로 나온다. sed는 기본적으로 한 줄씩 처리하여 출력하는데 두 줄을 하나로 합쳐놔도 라인피드(\n)가 그대로 남아있기 때문에 전혀 변하지 않은 것처럼 보이기 때문이다. 그리고 사실 아래 소개할 예제를 위해서 말고는 잘 안 쓰인다.
sed 'N;s/\n/ /' tem.txt

예제16: 검색해서 치환 후 모든 줄에 번호 넣기('=' 옵션 사용)
sed = tem.txt

예제17: 번호를 같은 줄에 넣기
sed = tem.txt | sed 'N;s/n/t/'


6. 검색 연산자(/단어/)
예제18: 한 단어를 검색해서 걸린 줄에서 작업하기
sed '/surendra/ s/audi/xyz/' tem.txt

예제19: 위를 응용해서 특정 범위의 줄 내에서 작업하기
sed '3,/Surendra/ s/audi/xyz/' tem.txt

예제20: 더 응용해서 찾은 단어가 있는 줄부터 문서 끝까지를 범위로 작업하기
sed '/Surendra/,$ s/audi/xyz/' tem.txt


7. 부정 연산자(!)
  이 연산자는 w, p, d 옵션과 함께 사용한다.
예제21: abc 라는 단어가 없는 모든 줄을 출력
sed –n '/abc/ !p' tem.txt

예제22: surenda 라는 단어가 있는 줄을 제외한 모든 줄을 삭제
sed '/surendra/ !d' tem.txt

예제23: 1~3 줄만 빼고 모든 줄 삭제
sed '1,3 !d'

2013/07/02 17:34 2013/07/02 17:34
Posted
Filed under 쉘 스크립트
참조 원문 : How to Write Linux Init Scripts Based on LSB Init Standard

  LSB란 Linux Standard Base의 약자로서 리눅스 재단이 배포판 사이의 차이점을 줄여 다른 배포판으로 이식할 때 드는 비용을 줄이기 위해 만든 표준입니다. Init 스크립트도 표준화된 것들 중 하나입니다.

  Init 스크립트는 소프트웨어나 서비스를 시작하거나 중단할 때 사용합니다. 예를 들어 postgresql 소프트웨어를 사용하고 있다면 /etc/init.d/postgresql 이라는 Init 스크립트를 가지고 있을 것이며 인자로 start, stop, restart, reload, force-reload, status를 사용할 수 있습니다.

  LSB 호환 Init 스크립트는 아래 사항을 지켜야 합니다.
  • 최소한 'start, stop, restart, force-reload, status'를 제공해야 한다.
  • 적절한 exit code를 return해야 한다.
  • 실행 의존성(run-time dependencies)을 문서화해야 한다.
  추가적으로 이 스크립트들은 메시지를 남기기 위해 "log_success_msg"나 "log_failure_msg" 같은 init.d 함수를 사용할 수 있습니다.

  LSB는 /lib/lsb/init-functions에 있는 기본 함수들을 제공합니다. Init 스크립트로 실행되는 프로세스들은 /var/run/ 디렉토리에 프로세스의 pid를 기록하는데 이것은 Init 스크립트가 프로세스의 상태를 조사할 때 큰 도움이 됩니다.

  이제 Init 스크립트를 작성해봅시다. 먼저 아래처럼 헤더를 넣습니다.
### BEGIN INIT INFO
# Provides:          my_daemon
# Required-Start:    postgresql networking
# Required-Stop:     postgresql networking
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: This is a test daemon
# Description:       This is a test daemon
#                    This provides example about how to
#                    write a Init script.
### END INIT INFO
  Provides에는 해당 Init 스크립트가 제공하는 기능(facility=서비스)을 적습니다. 이 이름은 유일해야 합니다.

  Requred-Start에는 이 서비스를 시작하기 전에 작동하고 있어야 하는 일련의 기능들을 적습니다. 이 예제의 경우 postgresql과 networking이 미리 실행되어 있어야 함을 나타내고 있습니다. 기억해야 할 점은 이 'postgresql'가 'Provides: postgresql'이라고 적힌 별도의 Init 스크립트를 가지고 있어야 한다는 것입니다. 이를 통해 부팅 시 의존성을 보장합니다. 'inserv' 명령어나 'update-rc.d' 명령어를 사용할 때 이 의존성을 바탕으로 대상 런레벨 디렉토리에 적절한 순번을 매겨 집어넣게 됩니다.
/etc/rc2.d/S12postgresql
/etc/rc2.d/S03networking
/etc/rc2.d/S13my_daemon
  예를 들어 위와 같은 엔트리가 있을 경우 networking, postgresql, my_daemon 순서로 실행됩니다.

  Required-Stop에는 이 기능을 중단한 후에만 중단할 수 있는 일련의 기능들을 적습니다. 이 예제의 경우 my_daemon이 중단된 후에만 postgresql과 networking 기능을 중단할 수 있습니다.

  Default-Start Default-Stop에는 이 서비스가 시작되거나 중단돼야 하는 런레벨을 정의합니다.

  Short-Description Description에는 해당 기능에 대한 설명을 적습니다. Short-Description에는 한 줄만 적을 수 있으며, Description에는 여러 줄에 걸쳐 적을 수 있습니다.

  아래는 실제 Init 스크립트의 예입니다.
### BEGIN INIT INFO
# Provides:          my_daemon
# Required-Start:    postgresql networking
# Required-Stop:     postgresql networking
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: This is a test daemon
# Description:       This is a test daemon
#                    This provides example about how to
#                    write a Init script.
### END INIT INFO

# Using the lsb functions to perform the operations.
. /lib/lsb/init-functions
# Process name ( For display )
NAME=my-daemon
# Daemon name, where is the actual executable
DAEMON=/home/user1/my_daemon
# pid file for the daemon
PIDFILE=/var/run/my_daemon.pid

# If the daemon is not there, then exit.
test -x $DAEMON || exit 5

case $1 in
 start)
  # Checked the PID file exists and check the actual status of process
  if [ -e $PIDFILE ]; then
   status_of_proc -p $PIDFILE $DAEMON "$NAME process" && status="0" || status="$?"
   # If the status is SUCCESS then don't need to start again.
   if [ $status = "0" ]; then
    exit # Exit
   fi
  fi
  # Start the daemon.
  log_daemon_msg "Starting the process" "$NAME"
  # Start the daemon with the help of start-stop-daemon
  # Log the message appropriately
  if start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON ; then
   log_end_msg 0
  else
   log_end_msg 1
  fi
  ;;
 stop)
  # Stop the daemon.
  if [ -e $PIDFILE ]; then
   status_of_proc -p $PIDFILE $DAEMON "Stoppping the $NAME process" && status="0" || status="$?"
   if [ "$status" = 0 ]; then
    start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
    /bin/rm -rf $PIDFILE
   fi
  else
   log_daemon_msg "$NAME process is not running"
   log_end_msg 0
  fi
  ;;
 restart)
  # Restart the daemon.
  $0 stop && sleep 2 && $0 start
  ;;
 status)
  # Check the status of the process.
  if [ -e $PIDFILE ]; then
   status_of_proc -p $PIDFILE $DAEMON "$NAME process" && exit 0 || exit $?
  else
   log_daemon_msg "$NAME Process is not running"
   log_end_msg 0
  fi
  ;;
 reload)
  # Reload the process. Basically sending some signal to a daemon to reload
  # it configurations.
  if [ -e $PIDFILE ]; then
   start-stop-daemon --stop --signal USR1 --quiet --pidfile $PIDFILE --name $NAME
   log_success_msg "$NAME process reloaded successfully"
  else
   log_failure_msg "$PIDFILE does not exists"
  fi
  ;;
 *)
  # For invalid arguments, print the usage message.
  echo "Usage: $0 {start|stop|restart|reload|status}"
  exit 2
  ;;
esac
  위 스크립트는 LSBInit 스크립트 작성을 위한 템플릿입니다. DAEMON, PIDFILE, NAME 변수, 헤더 등을 적절히 바꿔 사용할 수 있습니다.

  LSB가 제공하는 함수에 대해 더 알고 싶다면 InitScript Functions를 참조하시기 바랍니다.

  Init 스크립트를 작성한 후 자동으로 시작되거나 중단되게 만들려면 아래 형식으로 명령어를 실행합니다.(데비안 계열 기준)
update-rc.d filename defaults
  이 명령어는 지정한 런레벨에 의존성을 고려한 적절한 순번을 가진 'S'와 'K' 엔트리를 추가합니다.
2013/07/02 14:14 2013/07/02 14:14
Posted
Filed under 쉘 스크립트
원문 : http://www.linuxforum.com/threads/backup-all-databases-nightly-w-mysqldump.692/

  당일 날짜로 된 디렉토리를 만들어 그 안에 DB를 백업해 넣는 스크립트입니다.
#!/bin/bash

DB_BACKUP="/backups/mysql_backup/`date +%Y-%m-%d`"
DB_USER="root"
DB_PASSWD="secretttt"
HN=`hostname | awk -F. '{print $1}'`

# Create the backup directory
mkdir -p $DB_BACKUP

# Remove backups older than 10 days
find /backups/mysql_backup/ -maxdepth 1 -type d -mtime +10 -exec rm -rf {} \;

# Option 1: Backup each database on the system using a root username and password
for db in $(mysql --user=$DB_USER --password=$DB_PASSWD -e 'show databases' -s --skip-column-names|grep -vi information_schema);
do mysqldump --user=$DB_USER --password=$DB_PASSWD --opt $db | gzip > "$DB_BACKUP/mysqldump-$HN-$db-$(date +%Y-%m-%d).gz";
done

# Option 2: If you aren't using a root password then comment out option 1 and use this
# for db in $(mysql -e 'show databases' -s --skip-column-names|grep -vi information_schema);
# do mysqldump --opt $db | gzip > "$DB_BACKUP/mysqldump-$HN-$db-$(date +%Y-%m-%d).gz";
# done
  mysql의 root 계정 패스워드가 들어있기 때문에 퍼미션을 700으로 변경 후 cron에 등록하면 됩니다.
2013/06/23 17:03 2013/06/23 17:03
Posted
Filed under 쉘 스크립트
참조 원문 : Log Parser
#!/bin/bash

script=$(basename $0)_errors
log1=/var/log/messages
log2=/var/log/secure
log3=/var/log/dmesg

mydate=$(date +%b\ %d)

for log in $log{1,2,3}
do
if [ -e $log ] && [ -s $log ]
then
echo
echo BEGIN $log
grep -E "$mydate" $log | grep -E 'Device|fail'  2> $script
echo END $log
echo
fi
done
  필요한대로 수정한 후 cron으로 매일 23시 55분에 실행하면 적당할 것 같군요. 변수로 지정한 로그 파일들에서 당일 생성된 항목 중 지정한 키워드(위의 경우 Device나 fail)가 검출되면 해당 라인을 미리 정한 파일에 집어넣습니다. 간단해서 설명할 것도 없군요. 결과는 아래처럼 나오겠지요.
BEGIN /var/log/messages
Aug 31 01:21:43 mail kernel: pnp: Device 00:05 does not support disabling.
Aug 31 01:21:53 mail smartd[2046]: Device: /dev/hda, opened
Aug 31 01:21:53 mail smartd[2046]: Device: /dev/hda, not found in smartd database.
Aug 31 01:21:53 mail smartd[2046]: Device: /dev/hda, lacks SMART capability
Aug 31 01:21:53 mail smartd[2046]: Device: /dev/hda, to proceed anyway, use '-T permissive' Directive.
Aug 31 01:21:53 mail smartd[2046]: Device: /dev/hdc, opened
Aug 31 01:21:53 mail smartd[2046]: Device: /dev/hdc, packet devices [this device CD/DVD] not SMART capable
END /var/log/messages

BEGIN /var/log/secure
Aug 31 01:21:48 mail sshd[1872]: error: Bind to port 22 on 0.0.0.0 failed: Address already in use.
END /var/log/secure

BEGIN /var/log/dmesg
END /var/log/dmesg
  근데 많이 부실하긴 하네요. 나중에 좀 더 견고한 걸 올려야겠습니다.


2013/06/20 17:33 2013/06/20 17:33
Posted
Filed under 쉘 스크립트
참조 원문 : Line Addressing in sed

  sed 명령어를 통한 라인 어드레싱을 이용하면 필요한 줄만 골라 텍스트 작업을 할 수 있습니다. 이때 정규식을 사용할 수도 있죠. 두 숫자 사이에 콤마(,)를 사용하면 범위로 취급합니다.

1. 특정 범위를 출력
  file.txt 라는 파일에서 60번째부터 파일의 끝($로 표현)까지 출력하는 방법은 아래와 같습니다.
sed '60,$p' file.txt

2. 특정 범위의 줄을 삭제하여 출력
  file.txt 라는 파일에서 1~5번째 줄을 삭제한 후 "sshd"라는 패턴과 일치하는 줄을 출력하는 방법은 아래와 같습니다.
sed '1,5d' file.txt | sed -n '/sshd/p'

3. 특정 문자열을 원하는 문자열로 치환하여 출력
  file.txt 라는 파일에서 1~400번째 줄 사이에 있는 "pop3"라는 문자열을 "POP3"로 치환하여 그 내용을 file2.txt 파일에 저장하는 방법은 아래와 같습니다.
sed -n '1,400 s/pop3/POP3/p' file.txt > file2.txt
  sed 명령어는 입력 파일을 사용자가 원하는 대로 가공하여 출력만 할 뿐 원본 파일을 수정하지 않기 때문에 결과를 보관하고 싶다면 리다이렉션을 통해 별도의 파일로 저장해야 합니다.


2013/06/17 17:31 2013/06/17 17:31