안녕하세요, 타이젠 개발자 윤진입니다.


본 포스팅은 이틀에 걸쳐 졸음과 싸워가며 작성한 포스팅입니다.

오탈자가 있을 수 있으니 너그러운 맘으로 지적질(?) 부탁드립니다;


사실 이전 포스팅에서도 타이젠 개발환경의 핵심툴인 sdb를 언급한 적이 있습니다.

- sdb 설치하기 : [Tizen] 우분투에 타이젠 플랫폼 툴인 gbs & sdb 설치해보기

- sdb 사용하기 with Gear S2 : [Tizen/Gear S2] 타이젠 기어S2와 호스트 PC 연결하기


하지만 하루에도 수십차례 이용하는 sdb의 주요 기능에 대해 다룬 적이 없더군요.

어쩌면 지금 이 시간에도 수많은 타이젠 개발자들이 sdb를 이용하고 있을텐데요.

이 포스팅에서는 타이젠 개발자들이 주로 사용하는 sdb 기능을 설명하도록 하겠습니다.


sdb는 개발시스템과 디바이스(혹은 에뮬)을 연결하여 사용할 수 있도록 도와주는 툴입니다.

개발시스템과 에뮬 혹은 디바이스 혹은 에뮬과 디바이스를 동시에 연결할 수도 있지요.

파일을 주고 받고, 원격 쉘 접속을 위해 sdb를 사용하고 있습니다.


이런 sdb를 사용하기 위해서는 2가지 전제조건이 있습니다.


전제 1. 당연히, sdb를 설치하셔야겠지요.

sdb는 기본적으로 Tizen SDK와 함께 설치됩니다.

따라서 Tizen SDK를 설치하셨다면,

tizen-sdk/tools/sdb를 찾으실 수 있을겁니다.

만약 SDK 없이 sdb 툴만 리눅스환경에서 따로 받고 싶으시면 위에 언급한 포스팅을 참고해주세요.


전제 2. sdb로 붙이려는 디바이스의 debug 모드를 "On" 하셔야합니다.

디바이스에서 debug 모드를 켜놓지 않으면 sdb를 붙일 수 없지요.

타이젠 플랫폼에서는 Home > Settings > Device Info. > USB Debugging에서 설정하고,

타이젠 상품 Gear 시리즈에서는 Apps > Settings > Gear Info. > Debugging에서 설정하며,

타이젠 상품 Z1, Z3에서는 아래 포스팅을 참고해서 debug 모드를 설정하실 수 있습니다.

[Tizen] 타이젠 Z1에 개발자모드 메뉴가 숨겨져 있는 까닭은?


전제조건을 모두 만족하셨다면 이제 sdb 명령어를 살펴볼 차례입니다.

sdb 명령어는 도스나 리눅스 쉘에서 직접 사용할 수 있습니다.


sdb [option] <command> [parameters]


option에는 총 3가지 명령어가 있습니다.

옵션 1. "-d" 디바이스와 연결할 때 사용하는 명령어입니다.

개발시스템과 연결한 장치가 여러개 있을 경우,

그 중 USB와 직접 연결된 디바이스에 -d 옵션으로 접속할 수 있습니다.


옵션 2. "-e" 에뮬레이터와 연결할 때 사용하는 명령어입니다.

개발시스템과 연결한 장치가 여러개 있을 경우,

그 중 에뮬레이터에 -e 옵션으로 접속할 수 있습니다.

   

옵션 3. "-s" 시리얼넘버로 디바이스 혹은 에뮬에 접속할 수 있습니다.

시리얼 넘버는 sdb get-serialno 명령어로 얻을 수 있는데요,

앱개발할 때 사용한 경험이 거의 없군요 :)


위의 명령어 세가지는 말 그대로 옵션입니다.

개발시스템에 에뮬레이터와 디바이스가 모두 연결되어 있고,

둘 중 하나를 번걸아가며 접속할 때 유용하게 사용할 수 있습니다.

에뮬과 디바이스 중 하나만 접속이 되어 있다면,

옵션을 사용하지 않아도 접속된 에뮬 혹은 디바이스에 알아서 접속해줍니다.


command에는 다수의 유용한 명령어가 있습니다.

명령어 1. "root" <on | off>

root 명령어는 sdb로 에뮬 혹은 디바이스에 루트 권한으로 접속하게 해줍니다.

에뮬이나 플랫폼 바이너리가 탑재된 TM1 시료에서 사용할 수 있습니다.

Z1, Z3, Gear1, Gear2와 같은 상품에서는 root 권한을 얻을 수 없습니다.


명령어 2. "connect" <host>[:<port>]

connect는 Gear S2를 연결할 때 사용합니다.

이 명령어는 아래 포스팅을 참고해주세요.

[Tizen/Gear S2] 타이젠 기어S2와 호스트 PC 연결하기


명령어 3. "shell"

shell 명령어는 리모트쉘로 에뮬 혹은 디바이스에 접속할 수 있게 해줍니다.

쉘 명령어로 장치에 접속을 한뒤,

플랫폼에 설치된 다양한 명령어를 사용하여 장치의 상태를 확인할 수 있습니다.

top 혹은 ps를 사용하여 장치상태를 확인해보세요 :)


굳이 리모트 쉘에 접속할 필요없이,

쉘명령어만 한 번 사용하여 결과를 보고 싶다면,

sdb shell <명령어> 형식을 사용하면 됩니다.

예를 들어 ps 상황만 체크하고 싶다면,

sdb shell ps를 치면 쉘없이 ps 내용이 바로 출력됩니다.


명령어 4. "install" <pkg_path>

개발시스템에서 빌드한 패키지를 remote로 복사한 후 설치합니다.

패키지만 가지고 있는 경우,

sdb 명령어를 통해 쉽게 복사 & 설치할 수 있겠네요.


명령어 5. "uninstall" <pkg_id>

remote에서 패키지를 삭제할 때 사용할 수 있습니다.

이 때 pkg_id를 정확하게 알아야합니다.

자신이 삭제할 패키지의 ID는 정확히 알아야겠지요?


명령어 6. "push" <local> <remote>

개발시스템에서 빌드한 패키지를 에뮬 혹은 디바이스에 보낼 때 주로 사용합니다.

패키지 뿐만 아니라 각종 파일을 넘기는데 사용하지요.

<local>에는 개발시스템에서 보낼 파일을 기입합니다.

<remote>에는 파일을 받을 장소를 선택합니다.

만약 파일을 받을 디렉토리가 없다면 제대로 푸시되지 않을 수 있으니 미리 만들어주세요.

# sdb push file_to_push.txt /home/developer

위와 같이 file_to_push.txt 파일을 /home/developer 위치에 넣을 수 있습니다.


명령어 7. "pull" <remote> [<local>]

push와 상반되게 리모트 시스템에 있는 파일을 개발시스템으로 가져올 수 있습니다.

<remote>에는 리모트 시스템에 있는 파일을 절대경로로 적어주면 됩니다.

[<local>]을 적지 않으면 현재 디렉토리로 파일을 가져옵니다.


명령어 8. "kill-server" & "start-server"

sdb로 제대로 접속이 안될 경우,

sdb server를 죽였다가 다시 살립니다.

개발시스템과 에뮬 혹은 디바이스가 대부분 제대로 잘 붙는데요,

아주 간헐적으로 알 수 없는 이유 때문에 잘 안붙을 때가 있습니다.

그럴때 서버를 죽였다가 살려보세요. :)


명령어 9. "get-serialno" & "devices"

현재 접속된 디바이스 혹은 에뮬에 대한 시리얼 넘버를 알려줍니다.

여기서 얻은 값을 보고 위에서 설명드린 -s 옵션과 함께 사용하면 됩니다.


명령어 10. "dlog" [<filter_spec>]

개발시스템에 접속한 리모트장치의 상태를 dlog를 통해 엿볼 수 있습니다.

# sdb dlog

위의 명령어로 쉽게 로그를 출력할 수 있지요 :)


이상과 같이 간단하게 sdb의 명령어를 살펴봤습니다.

그럼 오늘도 즐거운 개발하시길... :)


끝_


안녕하세요, 타이젠 개발자 윤진입니다.


타이젠 플랫폼이 탑재된 기어S2를 구매하여 일주일째 사용하고 있습니다.

가급적이면 소비자의 시각에서 기어S2를 냉철하게 판단하고 싶지만 쉽지 않네요.

앱이 훅 죽어버린다거나 배터리가 광탈하면 심장이 덜컥 내려앉습니다.

결국 참다못해 기어S2를 호스트PC에 연결하여 여러가지 문제상황을 파악해보고자 합니다.


호스트PC와 기어S2를 연결하기 위해서는,

Tizen SDK 2.3.1 버전을 다운로드 받으셔야 합니다.

최종적으로 필요한 툴이 sdb(Smart Development Bridge)인데요,

sdb의 버전이 2.2.67 이후여야 기어S2가 제대로 인식됩니다.


Tizen SDK 2.3 버전인 경우,

sdb의 버전이 2.2.51이기 때문에 기어S2를 인식하지 못합니다.

2.3 환경에서 기어S2와 호스트PC를 연결해도 offline으로 인식하니 괜한 삽질하지 마세요~


Tizen SDK 2.3.1은 여기에서 받으실 수 있습니다.

현재 Tizen SDK 2.4가 최신 플랫폼입니다만,

Gear S2에는 Tizen 2.3.1 플랫폼이 탑재되었기에,

Gear S2용 앱을 개발하시려면 반드시 Tizen SDK 2.3.1을 설치하셔야 합니다.


기어S2는 cradle이나 extension으로 호스트PC와 연결하지 않습니다.

대신 기어S2를 호스트PC와 동일한 네트워크로 묶는 방식으로 연결합니다.

가정용 라우터가 있으면 호스트PC와 기어S2를 함께 연결해주세요.

물론, 기어S2는 무선으로 연결해야하겠지요?


1. 기어S2 디버깅모드 활성화



우선 기어S2의 디버깅 모드를 활성화해야합니다.

기어S2 오른편 하단 버튼을 눌러 Apps를 런칭합니다.

Apps > Settings(설정) > Gear info(Gear 정보) > Debugging(디버깅)

위처럼 진입하여 디버깅 모드를 활성화합니다.

디버깅 모드를 활성화해주어야 sdb를 붙여서 기어S2와 호스트PC를 연결할 수 있습니다.



2. 기어S2 와이파이 연결하기



기어S2를 라우터기에 연결할 차례입니다.

집에 무선 라우터기가 없으면 호스트PC와 연결할 수 없으니,

무선 라우터기가 없으신 분은 이 단계에서 무선을 지원하는 라우터기를 구매해주세요;


무선라우터기에 연결하기 위해서는,

Apps > Settings(설정) > Connections(연결) > Bluetooth(블루투스) > Bluetooth(블루투스)

블루투스를 우선 "비활성화"해주세요.

기어S2는 블루투스를 통해 와이파이를 연결하기 때문에,

블루투스를 꺼야 라우터에 수동으로 접속할 수 있습니다.


그리고,

Apps > Settings(설정) > Connections(연결) > Wi-Fi > Wi-Fi

위처럼 진입하여 Wi-Fi를 활성화해주세요.



Wi-Fi가 활성화되었다면,

Apps > Settings(설정) > Connections(연결) > Wi-Fi > Wi-Fi networks(Wi-Fi 네트워크)

위의 항목에 진입하여 연결된 라우터기를 선택합니다.

세부항목을 내려보면 IP 주소가 나오는데요,

이 주소로 호스트PC에서 접속할 수 있습니다.

위의 이미지 오른편에 보면 192.168.0.74라는 IP 주소가 나오네요.

이제 호스트 PC에서 sdb를 사용하여 기어S2에 연결할 수 있습니다.



우선 sdb 툴의 위치는 Tizen 2.3.1이 설치된 디렉토리 밑에 tools 디렉토리에 있습니다.

위의 예제에서는 기존에 사용하고 있던 sdb server를 죽이고 다시 띄웠는데요,

만약 기어S2에 연결이 안된다면 server를 죽이고 다시 띄운 후 시도해보세요.


$ sdb kill-server
$ sdb start-server


그리고 나서 sdb connect <IP주소>를 넣어 접속해주세요.

그러면 기어S2에 팝업이 하나 뜨는데요,

외부에서 접속하려고 하는데 의도한 접속인지 여부를 묻습니다.

확인버튼을 누르면 unauthorized에서 connected 상태가 됩니다.


자, 이제 연결이 다 되었습니다.

마음껏 탐험을 시작할 시간입니다.

아... root 권한이 아니어서 아음껏 탐험은 안되겠네요.

제한된 탐험이라도 즐겨보세요;


좋은 하루 보내세요~

끝_


* 본문에서 사용한 이미지 출처

http://developer.samsung.com/technical-doc/view.do?v=T000000251


  1. 코코콩 2015.11.19 20:51 신고

    안녕하세요 덕분에 타이젠2.3.1을 설치했네요... 웨어러블 sdk 설치하느라 며칠을 찾아보았는데 ㅎㅎ 감사합니다.
    그리고 문득 든 생각인데 타이젠이 성장하기 위해선 플래그쉽모델도 나와야하지않을까요? 물론 우선 앱생태계가 활성화되어야겠지만 듀얼OS로 지원을 해도 좋겠네요!

    오늘도 포스팅 잘보았습니다. 좋은하루되세요

    • 안녕하세요~ 코코콩님.
      이제 웨어러블의 세계에도 빠져드시겠군요 :)
      세상에 좋은 아이디어를 가진 사람이 많던데,
      웨어러블이라 가능한 재미난 앱을 만들어주세요~ 히힛.
      타이젠 플래그십 모델 출시 같은 큰 그림은 저 같은 일개 개발자 레벨에서는 잘 모르겠습니다. ㅠ_ㅜ
      멋지게 만들어놓으면 좋은 디바이스를 출시할 수 있겠죠~
      그럼 좋은 하루 보내세요~

  2. 전광하 2015.12.02 19:01

    안녕하세요.
    혹시, ip를 이용한 접근 말고, bluetooth 의 연결 상태에서는 sdb devices등의 제어를 할 수 없을까요?
    모단말과 gear s2는 거의 항상 블루투스로 연결되어 있어서, 모단말에서 제어를 해보고 싶은데요..
    궁금해서 문의 드립니다. 항상 감사합니다.

    • 안녕하세요,전광하님.
      현재로서는 ip를 이용하는 방법밖에 없습니다.
      하지만, 안드로이드를 라우터 삼아 웨어러블을 통제하거나,
      안드로이드에 올라가는 앱으로 웨어러블을 컨트롤하는 것도 재미있겠네요.
      좋은 의견 감사드리고 그냥 묻히지 않게 건의해보겠습니다.
      감사합니다.

  3. 보수동 2016.01.25 18:01

    안녕하세요? 타이젠으로 gear s2 에서 nfc app을 개발 중인 사람입니다. 실례가 되지 않는다면 질문을 좀 드리고 싶은데요. 타이젠에서는 nfc.tag feature 를 지원하는데 gear s2에서 지원을 하지 않는 것 같네요. 혹시 gear s2 에서 nfc.tag feature 를 언제 쯤 사용 가능할지 알 수 있을까요?

    • 안녕하세요, 보수동님.
      진심 대답해드리고 싶지만, 상품(Gear S2)의 피쳐에 대해서는 플랫폼 개발자가 알 수가 없어서요.
      지원여부는 http://developer.samsung.com/ 에서 문의하시는게 어떨까요?
      속시원한 답변을 드리지 못해 송구스럽네요.

    • 보수동 2016.01.26 00:09

      빠른 답변 감사합니다!!

    • 아, 넵. 감사합니다. 즐거운 하루 보내세요~!

  4. kykim 2016.01.30 21:23

    error: failed to connect remote target 'IP주소'만 계속 뜨네요...

    기어S2 블루투스, 3G 해제, 디버깅 ON, IP 주소 확인, 컴퓨터와 같은 네트워크 확인, sdb 버전 확인 다 했는데

    혹시 제가 빠트린 게 있을까요?

  5. 안녕하세요~ kykim님.
    같은 네트워크를 물리셨다는게 같은 라우터를 쓰셨다는것이지요?
    기어S2의 설정>네트워크에 들어가서 와이파이를 확인하면 네트워크 주소의 앞 세자리가 같은 라우터에 연결된 컴퓨터의 네트워크 앞 세자리와 동일한거죠?
    그렇다면 기본적으로 안될 이유는 없어보이는데요,

    그래도 아이피를 찾을 수 없다고 하니,
    기어의 와이파이를 다시 설정해보고,
    기어를 재부팅해보고,
    호스트피씨에서 sdb kill-server도 해봐야할 것 같습니다.

    꼭 연결에 성공하시면 좋겠네요.
    윤진 드림.

  6. 안녕하세요 2016.09.07 19:53

    지금 이 방식대로라면 혹여나 사진전송,파일전송같은 행위를 할수 있을까요?

  7. 노마십가 2019.05.03 03:57 신고

    혹시 게시글 대로 했음에도 error: failed to connect to remot tartget 에러가 발생하신다면,
    디버그 모드 킨 이후에는 꼭 디바이스 재부팅 해주세요 ㅠㅜ
    기기 재부팅 하고 나니까 잘붙습니다 흑흑

제어문과 변수까지 살펴보니 expr가 남았네요.

expr까지 간단하게 살피고 나서는,

쉘스크립트 자체 문법보다는 쉘스크립트와 함께 쓰이는 유용한 명령어들을 살펴보겠습니다.


쉘스크립트가 명령어를 좀 더 지능적으로 사용하려는 의도에서 만들어졌기 때문에,

이 다음부터가 본편이라 볼 수 있겠네요.



expr는 명령어로서 존재합니다.

$ ls /usr/bin/expr
/usr/bin/expr


하지만, bash 쉘은 expr를 built-in으로 내장시켰습니다.

쉘스크립트에서 expr 명령어를 사용하면,

/usr/bin/expr를 사용하지 않고 내장된 build-in 명령어를 실행합니다.

build-in 명령이 외부 명령보다 빠릅니다.

외부 명령어는 프로그램 로딩/런칭만으로도 하세월 보내겠죠.

물론, 굳이 외부 명령어를 사용하고 싶다면 절대경로를 지정해서 사용할 수 있습니다.


expr로 연산할 수 있는 내용은 아래 4가지 입니다.

- 산술 : +, -, *, /, %

- 논리 : |(or), &(and)

- 관계 : =, >, >=, <, <=, !=

- 문자열 : ':'(일치 혹은 substitute)


expr도 명령어이기 때문에 연산자와 피연산자는 (space)로 구분되어야 합니다.

아래와 같이 공백을 안주면 5+1을 하나의 문자열로 인식합니다.

$ expr 5+1
5+1

아래와 같이 공백을 주어야 제대로 답이 계산됩니다.

$ expr 5 + 1
6


연산자로 쓰이는 기호 중 일부는 이미 특수문자로 사용되고 있습니다.

특수문자 : '*' all, '&' bg, '|' pipe, '>', '<' redirection, '(', ')' grouping

위의 문자를 연산에 사용하려면 쉘스크립트가 낚아채서 다른 부호로 오해하지 않게,

각 부호 앞뒤로 따옴표로 감싸주거나 부호 앞에 escape 문자인 '\'를 붙입니다.

$ expr 5 '*' 2
10
$ expr 5 "*" 2
10
$ expr 5 \* 2
10


만약 expr에 사용되는 인수들을 통째로 따옴표처리하면,

expr에 연산자 / 피연산자의 구분되어 처리되지 않고 하나의 문자열로 취급됩니다.

$ expr '5 * 3'
5 * 3


'=' 연산은 좌우의 피연산자의 값이 같으면 1(true)을 출력하고 다르면 0(false)을 출력합니다.

여기서 '출력'의 의미는 '리턴값'과 다른 것에 주의합니다.

'출력'은 true의 경우 1이고, false의 경우 0입니다.

하지만 '리턴값'은 true인 상황에서는 0이고 false인 상황에서는 1이지요.

값에서 보면, '출력'과 '리턴값'은 서로 반대이기 때문에 헛갈릴 수밖에 없습니다.

$ a=5
$ expr $a = 5
1
$ echo $?
0
$ expr $a = 4
0
$ echo $?
1
$ expr $a = '5 * 3'
0
$ echo $?
1

이렇게 된 연유는 '리턴값'에 대한 유닉스 고유의 정책때문입니다.

유닉스에서는 에러없이 성공적으로 프로그램이 종료되면 '0'을 리턴합니다.

문제가 있으면 '0' 외에 다른 값을 출력합니다.

따라서 쉘스크립트에서도 '0'인 경우를 '성공'으로 판단합니다.


하지만 일반적인 프로그래밍 언어에서는 '1'은 true이고 '0'은 false입니다.

expr가 출력하는 값은 일반적인 프로그래밍 언어에서 사용하는 방식 그대로입니다.

이 부분은 오랜 시간 규약처럼 정해져서 이제는 바꾸기 힘들겁니다.

이에 대한 이야기는 나중에 할 기회가 또 오겠지요.


$ E="="
$ expr $E = "="
1

위와 같은 경우에는 마치 등호가 세 개 나란히 쓰인 것처럼 보이겠네요.

하지만, 가운데 등호만 등호로 인식되고,

좌우의 등호기호는 피연산자인 문자로 인식됩니다.

쉘 버전에 따라 좌우에 있는 '='도 연산자로 인식하여 오류가 나는 경우도 있습니다.


따라서 연산기호를 사용한 변수를 위해 변수 앞에 문자열 'x'를 붙여서 비교할 수 있습니다.

$ expr x$E = x"="
1

'x' 문자를 붙이면 변수가 null이더라도 제대로 비교가 되지요.


expr 명령어가 리턴값 외에 출력값이 있으니 출력값을 제거하고 싶을 때도 있을겁니다.

그럴 때는 redirection을 이용합니다.

$ a=7
$ expr $a = 7 > /dev/null && echo $a
7

/dev/null로 출력을 보내버리면 더 이상 화면에는 아무 것도 출력하지 않습니다.

하지만, &&가 연달아 붙어있습니다.

expr 명령문 자체가 성공을 의미하는 '0'을 리턴하므로,

&& 뒷편의 명령어도 실행이 됩니다.

echo $a에 의해 최종적으로 a 변수값이 출력되었습니다.


$ expr $a = 8 > /dev/null && echo $a

반면 위와 같이 $a가 7인데 8과 비교를 하였다면, 결과값은 실패를 의미하는 1이 나옵니다.

결과가 1이면 &&의 뒷부분은 실행되지 않습니다.


이제 logical 비교를 수행해보겠습니다.

$ expr "" \| ""
0
$ echo $?
1

null값 두 개를 oring(|) 해봤자 결과는 null입니다.

false를 의미하는 0을 출력하였고, 실패라는 의미의 '1'을 리턴하였습니다.


$ expr "" \| 0
0
$ echo $?
1

null과 0을 oring(|) 해도 결과는 false입니다.


반면 피연산자 중 하나가 1이거나 문자라면 결과는 true가 됩니다.

출력값은 1 혹은 문자가 나옵니다.

$ expr "" \| 1
1
$ echo $?
0
$ expr "" \| "a"
a
$ echo $?
0


$ expr "a" \| "hello"

위의 출력값은 무엇일까요?

"a"에서 이미 oring의 결과가 결정되었습니다.

따라서 출력은 "a"입니다.


and 연산은 피연산자 중에 하나가 null 혹은 0이면 출력은 언제나 '0'이 됩니다.

$ expr '' \& ''
0
$ echo $?
1
$ expr "" \& ""
0
$ echo $?
1
$ expr "" \& 1
0
$ echo $?
1
$ expr "" \& "a"
0
$ echo $?
1

리턴값은 실패를 의미하는 1입니다.


$ expr 1 \& "a"
1
$ expr "a" \& 1
a

양쪽에 값이 있으면 앞쪽에 나온 값이 출력값이 됩니다.

리턴값은 당연히 성공을 의미하는 0입니다.


":" 연산은,

string : 정규표현식

위와 같은 형태로 사용합니다.

string 문자열 내에서 정규표현식에 부합하는 문자열의 길이를 출력합니다.

$ expr story : story
5
$ echo $?
0
$ expr story : storycompiler
0
$ echo $?
1
$ expr storycompiler : story
5
$ echo $?


하지만 정규표현식은 string의 제일 첫 문자부터 일치여부를 가립니다.

$ expr compiler_of_story : story
0

위처럼 string에 story가 있음에도 불구하고,

출력값은 false를 뜻하는 0이 나왔습니다.


$ a="1234abcd"
$ expr $a : [^a-zA-Z]*[a-zA-Z]
5
$ expr $a : [^a-zA-Z]*[a-zA-Z]*
8

위처럼 복잡하게 정규식을 사용하여 정규식에 일치하는 문자개수를 출력할 수 있습니다.

마지막에 '*' 유무에 따라 "1234a" 혹은 "1234abcd"까지 일치하지요.


expr에 괄호를 사용하여 괄호 안에서 매치되는 부분만 출력할 수 있습니다.

$ expr "$a" : '[0-9]*\([a-z]*\)'
abcd
$ expr "$a" : "[0-9]*\([a-z]*\)"
abcd

a변수는 "1234abcd"인 경우,

[0-9]*에 의해 1234가 매치됩니다.

그리고 그 뒤에 괄호에 의해 abcd가 매치가 됩니다.

expr는 괄호 내에서 매치되는 부분이 있으면 그 내용을 출력합니다.

매치된 문자 개수말고 매치된 내용을 출력하게 되지요.


$ expr "$a" : [0-9]*\([a-z]*\)
0

단, 위처럼 ""나 ''로 정규식을 감싸지 않으면 매치된 문자열을 출력하지 않습니다.

따옴표로 감싸진 부분만 스트링으로 인지하여 출력합니다


여태까지 살펴본 expr의 수많은 연산자들 사이에는 우선순위가 있습니다.

총 7단계로 나눌 수 있습니다.

1. 괄호

     괄호는 다른 모든 우선순위를 능가합니다. 어느 언어에서나 마찬가지이죠.

2. string : 정규식

     문자열에서 정규표현식을 부분이 괄호를 제외하고 가장 높습니다.

3. *, /, %

     곰셈, 나눗셈, 나머지 연산

4. +, - 

    덧셈, 뺄셈

5. =, >, >=, <, <=, !=

    관계

6. &

    and연산

7. |

    or 연산


이상과 같습니다.

우선순위가 확실히 기억나지 않는다면 괄호로 감싸주면 되겠지요.


오늘은 여기까지 하겠습니다

그럼 좋은 하루 보내세요~

끝_


* References

http://www.grymoire.com/Unix/Sh.html#uh-84

  1. dn 2016.07.14 17:53

    좋은정보감사합니다!!!ㅠㅠ

  2. 뉴트리노개미 2016.11.06 11:59

    리눅스 쉘 프로그래밍 배우는중에 연산자가 어떤 종류가 있나 해서 들어왔는데 굉장히 자세한 예제를 들어 설명해주셔서 많은 정보를 익히고 갑니다. 감사합니다 ㅎㅎ

쉘스크립트에서 변수를 빼먹으면 안되죠~

어쩌면 가장 먼저 다뤄야했을 내용일지도 모르겠네요.

워낙 두서없이 생각나는 순서로 정리하다보니 뒤로 미뤄졌습니다.

하지만 그렇다고 해서 그 우선순위에서 밀린다는 얘기는 절대로 아닙니다.



변수명은 영문자, 숫자 그리고 '_'(underscore)로만 이뤄집니다.

그 외의 문자는 변수명으로 인식하지 못합니다.

따라서 $FILE.old라는 문장에서 $FILE만이 변수명이 될 수 있습니다.

".old"부터는 "." 때문에 변수명이 될 수 없습니다.

그저 변수명 뒤에 연달아 나온 스트링으로 인식됩니다.


$ touch secret
$ FILE=secret
$ mv $FILE $FILE.old
$ ls secret*
secret.old

위의 예에서는 먼저 secret란 파일을 만든 후,

$FILE 변수를 사용하여 secret.old로 파일이름을 바꿉니다.

변수명과 '.old' 사이에 빈칸이 없어도,

'.'이 변수명의 범주에 들지 않기 때문에 '.' 뒤부터는 자연스레 스트링으로 인식됩니다.

다른 고급언어에서는 이와 같은 상황에서 에러를 출력하지만,

쉘스크립트에서는 이런 모호함도 처리해주네요.


이와는 대조적으로 '.' 대신 '_'를 사용하면 모두 변수명이 됩니다.

$ mv $FILE $FILE_new
mv: `secret' 다음에 대상 파일 명령이 누락

위처럼 $FILE_new는 'FILE_new'라는 이름의 변수일 뿐입니다.

변수에는 아무것도 넣어져 있지 않기 때문에 NULL입니다.

그래서 명령이 누락되었다는 메시지가 나오지요.


굳이 $FILE 변수값에 '_'가 포함된 스트링을 덧붙이고 싶다면,

아래에 명시된 방법 중에 하나를 사용하면 됩니다.

mv $FILE $FILE"_new"
mv $FILE $FILE'_new'
mv $FILE $FILE""_new
mv $FILE $FILE''_new
mv $FILE "$FILE"_new


큰따옴표를 변수명쪽에 붙이든 스트링쪽에 붙이든 결과는 같습니다.

흥미로운건 변수명과 스트링 사이에 따옴표를 넣어도 결과는 같다는 것이겠죠?

왜 그런걸까요?

""는 고급언어처럼 스트링을 나타내는 상징이 아닙니다.

스크립트에서는 ""는 따옴표 안에 있는 요소를 그룹으로 묶는 기능이 있습니다.

따옴표 안으로 넣어 그룹이 되면 그 밖의 요소는 그룹에 속하지 않은 요소가 됩니다.

좌우도 구분지어지겠지요.


mv $FILE $FILE\_new

'\'는 escape 문자처럼 동작하는데요,

변수와 스트링을 구분할 때도 사용됩니다.

변수명 뒤에 오는 '\'는 영문이나 숫자 혹은 '_'가 아니기 때문에 변수명이 될 수 없습니다.

그렇다면 당연히 변수명은 '\' 앞글자까지겠죠.

$ echo "\_str"
\_str
$ echo '\_str'
\_str


일반적으로 큰따옴표나 작은따옴표로 "\_"를 출력하면 역슬래시도 그대로 나옵니다.

왜냐하면 "_"는 escape 없이도 표현할 수 있는 문자이기 때문입니다.

하지만, 따옴표 없이 "\_"를 출력하면, 역슬래시는 없어지고 "_"만 출력됩니다.

비단 '_' 뿐만 아니라 어떤 글자가 와도 역슬래시는 표시되지 않습니다.


쉘단에서 따옴표 없는 \는 다음 문자를 연속되는 문자로 취급되게 해줍니다.

곧 변수명이 치환된 후에 이어서 오는 문자열과 자연스럽게 합쳐지지요.

$ echo \_str
_str
$ echo \+
+
$ echo \-
-
$ echo \a
a


변수명을 보다 확실하게 확정짓는 방법이 있습니다.

변수명 좌우로 괄호 {, }를 치면 됩니다.

괄호영역 내에 있는 이름이 변수명이 됩니다.

mv $FILE ${FILE}_new


이상으로 변수명에 대해 전반적으로 훑어보았습니다.

이제는 변수값을 지정하는 여러가지 방법에 대해 따져보겠습니다.


괄호에는 단지 변수명만 들어가지 않습니다.

$ cat ${NO_VARIABLE? No variable}
bash: NO_VARIABLE:  No variable
$ echo $?
1

위처럼 변수명이 정의되지 않았을때 물음표 뒤의 문장을 출력할 수 있습니다.

대신 에러(1)가 리턴되므로 조건문/반복문에서 제대로 처리해야합니다.


괄호 안에 '-'가 들어가는 경우도 있습니다.

'-'는 변수가 정의되지 않은 경우에만 적용하라는 의미입니다.

$ echo ${NO_VARIABLE-$HOME}
/home/storycompiler
$ echo $?
0

NO_VARIABLE 변수가 사전에 정의되지 않았다면,

$HOME 값이 대입됩니다.


괄호 안에 '+'를 추가할 수도 있습니다.

'+'는 '-'기호와 반대의미를 가집니다.

'-'가 선언되지 않았을때 사용한다면,

'+'는 선언되었을때 사용합니다.

$ echo ${HOME+"home is set"}
home is set
$ echo $?
0

위의 예에서 $HOME변수가 선언되어 있으면 뒤의 문자열을 출력합니다.


괄호 안에 '='를 사용한다면,

'='의 의미답게 변수에 값이 있든 없든 관계없이 '=' 뒤의 값이 대입됩니다.

$ echo ${NO_VARIABLE=variable}
variable
$ echo ${NO_VARIABLE}
variable


정리하자면,

"?"는 정의되어 있지 않으면 뒤의 문자열을 출력하고,

"+"는 정의 되어 있어야 뒤의 문자열을 출력합니다.


"-"는 정의되어 있지 않으면 뒤의 문자열을 대입하고,

"="는 "-"와 동일합니다.

대입과 출력의 차이가 있습니다.


'?', '-', '+', '=' 앞에 ':' 문자를 사용할 수도 있습니다.

':' 문자는 null로 define 된 경우까지 추가하여 각 연산을 강화합니다.


$ A=""
$ echo ${A? "undefined"}

$ echo ${A:? "undefined or null"}
bash: A:  undefined or null


위와 같이 A에 ""를 대입하면, 변수 A는 defined 상태입니다.

따라서 ${A? "undefined"}에서 "undefined" 문자열을 출력하지 않지요.

하지만 ':'를 붙이게 되면, null로 정의된 경우도 검출이 됩니다.

곧, ?는 정의되지 않으면 출력하지만,

:?는 정의되지 않은 것 뿐만 아니라 null로 정의되더라고 출력합니다.


"+"는 정의된 경우에만 문자열을 출력했다면,

":+"는 null이 아닌 값이 정의되어 있는 경우에만 문자열을 출력합니다.


"-"는 정의되어 있지 않으면 문자열을 대입했지만,

":-"는 변수에 값이 정의되지 않았거나 null로 대입된 경우에 뒤의 문자열을 대입합니다.

":="는 ":-"와 동일합니다.


$ echo ${A+"defined"}
defined
$ echo ${A:+"defined"}
(공백)


"+"의 경우, A가 정의되어 있으면 defined를 출력합니다.

":+"의 경우, null로 정의되어 있기 때문에 ":+" 뒤의 문자열을 출력하지 않습니다.


이상으로 변수에 대한 이야기를 마치겠습니다.

그럼 좋은 하루 보내세요~

끝_




* References

http://bash.cyberciti.biz/guide/Rules_for_Naming_variable_name


사용자 계정으로 로그인한 후

간혹 관리자 root 권한이 필요할 때가 있습니다.


패키지를 설치하거나,

시스템 설정 파일을 수정하거나,

신규유저를 추가하거나,

다른 계정으로 파일권한을 변경하거나

root 권한을 광범위하게 사용하고 있습니다.


root 권한으로 변경할 때 가장 친숙한 명령어가 su입니다.



su는 substitute user의 줄임말입니다.

현 사용자를 로그아웃하지 않고, 다른 사용자의 권한을 획득할 때 사용하죠.

단일 사용자계정으로 우분투 데스크탑을 사용하고 있는 경우에도,

사용자의 권한을 루트로 변경할때 자주 사용합니다.


사용법 : su [변경하고자 하는 사용자 ID]


su 뒤에 변경할 사용자 ID를 입력하지 않는다면,

su root와 동일하게 동작합니다.


$ su
Password: 
# exit
logout
$


위처럼 일반계정쉘 $이 보이다가,

su root로 변경된 후 관리자계정쉘 #로 변경되는 것을 볼 수 있습니다.


하지만 su 뒤에 -를 붙이면 동작방식이 달라집니다.

‘-’의 의미는 무엇일까요?


‘-’

‘-l’

‘--login’

Make the shell a login shell. This means the following. Unset all environment variables except TERM, HOME, and SHELL (which are set as described above), and USER and LOGNAME (which are set, even for the super-user, as described above), and set PATH to a compiled-in default value. Change to user's home directory. Prepend ‘-’ to the shell's name, intended to make it read its login startup file(s). 


‘-’는 -l 혹은 --login과 동일한 명령어입니다.

곧, su -는 su --login root와 동일한 명령인 셈입니다.

위의 설명에서 언급되어 있듯,

‘-’의 유무는 환경변수와 워킹디렉토리에 영향을 줍니다.



위의 표를 하나씩 살펴보기로 하죠.

환경변수 TERM, HOME, SHELL, USER, LOGNAME는,

su나 su -나 모두 변경된 사용자 ID에 맞게 재설정됩니다.


HOME과 SHELL은  /etc/passwd에서 변경할 사용자의 정보를 가져와서 설정합니다.

USER와 LOGNAME은 변경할 사용자계정을 입력하지요.


PATH는 su에선 변경 전후가 동일하지만,

su -에선 PATH가 컴파일시 설정한 default 값으로 설정됩니다.


그 외의 환경변수는 분명한 차이가 있죠.

su는 기존 사용자 환경에서 설정된 환경변수를 그냥 그대로 유지합니다.

그에 반해, su -는 기존 사용자 환경에서 사용하던 환경변수를 모두 지워버립니다.


$ export hello=tizen
$ su
암호:  # echo $hello tizen # exit $ su - # echo $hello (null)

위의 예를 살펴보시죠.

기존 사용자 계정에서 hello라는 변수에 tizen이라는 값을 넣어두었습니다.

그리고 su로 관리자 계정으로 변경합니다.

su는 기타 환경변수를 유지하기 때문에 hello의 환경변수값이 tizen으로 나오겠지요?

위의 예에서도 echo $hello를 하니 tizen이 나오네요.


그리고 exit하여 원래 계정으로 복귀한 후,

이번엔 su -를 합니다.

그리고 echo $hello를 해봅니다.

이번에는 아무 것도 나오지 않네요.

--login 옵션으로 환경변수가 정리되었기 때문입니다.


그리고, su는 워킹디렉토리를 변경하지 않습니다.

반면 su -는 변경한 사용자 계정의 홈디렉토리로 이동하게 됩니다.


$ pwd
/tmp
$ su
암호: 
# pwd
/tmp
# exit
exit
$ su -
암호: 
# pwd
/root


최초에 /tmp 디렉토리에 있었고,

su를 해도 여전히 /tmp에 머물고 있습니다.

하지만, su -를 하면, 관리자 계정의 홈디렉토리인 /root로 이동하게 됩니다


위의 차이점을 알고 사용하면 됩니다.

워킹디렉토리는 cd로 변경하면 그만이니,

환경변수 설정부분만 유의하면 되겠네요.

환경변수는 빌드/실행에 영향을 줄 수 있으니까요.


끝_



* References

http://ko.wikipedia.org/wiki/Su_%28%EC%9C%A0%EB%8B%89%EC%8A%A4%29

http://www.gnu.org/software/coreutils/manual/html_node/su-invocation.html



+ Recent posts