man bash의 내용 순서대로 정리를 합니다. Bash 4.3.xx 기준이기 때문에 Mac OS X 3.2.xx에서는 동작하지 않는 명령도 존재합니다.

OPTIONS

  • -c

    $ bash -c 'echo $0 $1' command arg1
    command arg1
    

SHELL GRAMMAR

  • Simple commands
    • 환경 변수 설정 및 리디렉션까지를 포함한다.
    • ; ;; & && || | |& ( ) <newline>으로 다른 command와 구분이 된다.

      $ JEKYLL_ENV=production jekyll build >output
      
  • Pipelines
    • 여러 command를 pipe로 연결해서 실행할 수 있다.
    • exit status는 마지막 command의 exit status
      • 이 경우에는 도중에 에러가 발생하면 알 수 없으므로 pipefail 옵션을 이용해서 모두 0을 리턴한 경우에만 0을 리턴하도록 할 수 있다.
    • time [-p]을 앞에 붙이면 전체 실행 시간을 표시해 준다.
    • 2>&1 | 와 같이 리디렉션이 함께 있을 경우에는 pipe에 의한 fd의 변경이 먼저 일어나고 그 후에 리디렉션이 일어난다.
    • 2>&1 ||& 와 같다.

      # 각 command에 대해서 stderr를 별도의 파일로 저장
      $ time ls 2>ls.error | sort 2>sort.error | uniq 2>uniq.error
      
      # ls의 stdout이 아닌 stderr를 pipe로 전달하기. fd 3은 1, 2 번의 swap에 사용하기 위한 임시 fd
      $ ls -z 3>&1 1>&2 2>&3 | tee ls.error
      
  • Lists
    • 여러 pipeline의 모임
    • ;, &, &&, ||로 개별 pipeline이 구별된다. &, ;, <newline>으로 list는 끝난다.
    • &&, ||의 우선 순위가 ;, & 보다 높다.
    • &&, ||의 우선 순위는 동등하다. &&가 더 높지 않다는 것에 주위하라.

      # &&이 아닌 || 부터 실행이 되기 때문에 1, 3이 출력된다.
      $ echo "1" || echo "2" && echo "3" & echo "4"
      [1] 36066
      4
      1
      3
      [1]+  Done                    echo "1" || echo "2" && echo "3"
      
      # background 실행을 한 줄에 실행하는 것이 가능하다.
      $ find dir1 | sort >list1 & find dir2 | sort >list2 &
      
  • Compound Commands
    • (list)
      • subshell로 실행
    • { list; }
      • 세미콜론이나 newline으로 list가 종료
      • 공백이 있어야 한다.
    • ((expression))
      • ARITHMETIC EVALUATION
      • 0이 아닌 경우의 return status가 0이 된다.

        $ if ((1+1));then echo "OK";fi
        OK
        
      • let "expression" 과 동일
    • [[ expression ]]
      • CONDITIONAL EXPRESSIONS
      • Tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, quote removal은 적용된다.
      • Pathname expansion은 적용되지 않는다.

        # $a, *에 대해서 pathname expansion이 발생해서 [ 를 이용하는 경우에는 에러 발생
        $ a='*'; if [ $a = * ];then echo "YES";fi
        -bash: [: too many arguments
        
        # $a, *를 모두 quote를 해서 해결
        $ a='*'; if [ "$a" = "*" ];then echo "YES";fi
        YES
        
        # pathname expansion이 발생하지 않는다.
        $ a='*'; if [[ $a = * ]];then echo "YES";fi
        YES
        
      • Word splitting은 적용되지 않는다.

        # $a에 대해서 word splitting이 발생해서 [ 를 이용하는 경우에는 에러 발생
        $ a="abc def"; if [ $a = "abc def" ];then echo "YES";fi
        -bash: [: too many arguments
        
        $ a="abc def"; if [ "$a" = "abc def" ];then echo "YES";fi
        YES
        
        # Word splitting이 발생하지 않는다.
        $ a="abc def"; if [[ $a = "abc def" ]];then echo "YES";fi
        YES
        
    • for name [ [ in [ word … ] ] ; ] do list ; done
      • in word가 생략되면 positional parameter($1, $2, …)에서 읽어온다.

        # 아래의 두 명령을 같다.
        for i         do echo $i;done
        for i in "$@";do echo $i;done
        
    • for (( expr1 ; expr2 ; expr3 )) ; do list ; done
      • expr이 없는 경우에는 1로 처리

        $ for ((i = 0; i < 3; i++));do echo $i;done
        0
        1
        2
        
    • select name [ in word ] ; do list ; done
      • 주어진 목록이 화면에 번호와 함께 표시되고 사용자가 선택시 name이 값이 저장된다.
      • PS3에 원하는 프롬프트를 지정할 수 있다.
      • EOF(CTRL+D)로 끝낼 수 있다.

        $ PS3='Which file to delete? ';select i in *;do rm $i;done
        1) BashPlayground    5) file1        9) list2           13) readnum.sh  17) uniq.error  21) xad     25) xxx
        2) a b               6) file2       10) ls.error        14) run_get.sh  18) xaa         22) xae
        3) cut.sh            7) input.txt   11) no_in_word.sh   15) sort.error  19) xab         23) xaf
        4) diff.sh           8) list1       12) outfile         16) test.sh     20) xac         24) xag
        Which file to delete? 25
        rm: xxx: is a directory
        Which file to delete? 21
        Which file to delete? ^D
        
    • case word in [ [(] pattern [ | pattern ] … ) list ;; ] … esac
      • ;; 는 C switch 문의 break와 같은 역할을 한다. 버전 4.X 부터 ;;&, ;& 추가된 것으로 보임.
      • ;; 대신에 ;&를 사용하면 C switch 문에서 break가 없는 것과 같다. (pass through)
      • ;;& 를 사용하면 나머지 pattern에 대해서도 비교를 계속 수행한다.
      • word에는 다음의 expansion이 적용된다.
        • tilde expansion, parameter and variable expansion, arithmetic substitution, command substitution, process substitution and quote removal
      • pattern에도 다음의 expansion이 적용된다.
        • tilde expansion, parameter and variable expansion, arithmetic substitution, command substitution, and process substitution
      • 비교는 파일 이름 비교(glob pattern) 방법을 사용한다.

        $ cat case.sh
        #!/bin/bash
        filename=$1
        case $filename in
            * )
                echo "File $filename:"
                ;;&
            *jpg | *png | *bmp )
                echo "image file"
                ;;&
            *.* )
                echo "extension exist"
                ;;&
        esac
        
        $ ./case.sh a.bmp
        File a.bmp:
        image file
        extension exist
        
        $ ./case.sh a.txt
        File a.txt:
        extension exist
        
        $ ./case.sh a
        File a:
        
    • if list; then list; [ elif list; then list; ] … [ else list; ] fi

    • while list-1; do list-2; done
    • until list-1; do list-2; done
      • until은 while의 조건에 not 을 한 것과 같다.

        $ x=3;while ((x--));do echo $x;done
        2
        1
        0
        
        $ x=3;until ! ((x--));do echo $x;done
        2
        1
        0