본문 바로가기

엔지니어/Bash

Bash 트릭 몇가지

728x90
반응형
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의 출력을 읽는다. 이 기술은 임시 파일이 필요할 때 쓸 수 있지만 제한사항이 있다. 이 임시 파일은 사라지기 전에 한 번만 읽을 수 있다. 임시 파일의 이름을 보관했다가 나중에 사용하는 것은 불가능하다는 것이다. 프로그램의 출력을 여러 번 참조해야 한다면 그냥 임시 파일을 만들거나 파이프를 써야 한다.


반응형

'엔지니어 > Bash' 카테고리의 다른 글

파일유무  (0) 2016.05.26
mysql backup  (0) 2016.05.26
geoip  (0) 2016.05.26
expect rsync  (0) 2016.05.26
Bash 의 잘 알려지지 않은 기능 7가지  (0) 2016.05.26