12월이 벌써 다가왔습니다. 2025년도 어느덧 한달을 남겨두고 있는데요..
남은 2025년 열정을 불태우며 마무으리! 해보게쑵니다..

Linux

Bash의 확장

  • 중괄호 확장 : { }를 사용해 문자열 시퀀스나 조합을 생성하는 것

    $ ls
    $ echo hello-{cat,dog,world}  # 조합이 가능 
    hello-cat hello-dog hello-world
    $ echo hello-{cat,hello dog,world}  
    hello-{cat,hello dog,world}
    # => 공백이 들어가면 그냥 그대로 출력  공백을 넣고 싶다면 \를 넣으면 된다.
    
    " " : double quote 사용시 그냥 문자열 그대로 출력
    $ echo hello-{cat,hello-{dog,monkey},world} # 중첩 가능
    hello-cat hello-hello-dog hello-hello-monkey hello-world
    => 이렇게 확장도 가능 
    $ echo {z..a}
    z y x w v u t s r q p o n m l k j i h g f e d c b a
    => 순서대로 출력
    $ echo {1..9..2}  # for문과 같은 반복문에 유용하게 사용
    1 3 5 7 9
  • 틸데 확장 : 물결표가 홈 디렉터리로 변환되는 것

    cd ~ => 홈 디렉토리로 이동
    ~+ => 현재 작업 디렉토리. 
    ~- => 이전 디렉토리 ⭐️
  • 명령어 치환 : $()로 둘러싸인 명령어를 실행하고 그 결과를 쉘의 명령어나 스크립트에서 활용

    $ echo $(pwd)
    /home/ros2man/shell_Practice
    $ echo $OLDPWD
    /home/ros2man
    => 바로 이전에 작업하던 디렉토리 경로 저장하는 변수 (Linux에서 사용)
    
    $ echo $(PWD)
    PWD: command not found 
    -> $()는 명령어로 들어감
    
    $ thistime=$( date +"%Y-%m-%d %H:%M:%S") #변수를  넣기 위해서는 공백이 있어서는 안된다.
    $ echo $thistime
    2025-12-01 09:39:34
  • 산술 확장 : $(()) 나 이중 괄호로 감싼 표현식을 산술 연산해 그 결과를 스크립트에서 사용할 수 있게 하는 것.

    noa$ thistime=$( date +"%Y-%m-%d %H:%M:%S") #변수를  넣기 위해서는 공백이 있어서는 안된다.
    $ echo $thistime
    2025-12-01 09:39:34
    
    #func_com_sub.sh 작성
    function magic_box_with_progress()
    {
            input="$1"
            let "result = input + 8"
            echo "$input + 8 = $result"
            return $result
    }
    progress=$(magic_box_with_progress "7")
    result="$?"
    echo "progress: $progress"
    echo "result is $result"
    #실행결과
    $ ./func_com_sub.sh 
    progress: 7 + 8 = 15
    result is 15
    -------------------------------------------
    $ let "result = 8*2"
    $ echo $result
    16
    $ declare -i iv #변수를 int형으로 선언
    $ iv=$iv+1
    $ echo $iv
    1
    $ iv+=1
    $ echo $iv
    2
    ------------이와 같은 표현이 가능

    그냥 var = $var4를 하면 var는 문자열로 해석하기 때문에 var값 4가 출력된다

    산술 연산이 가능한 경우

    1. 산술 확장 (( ))
    2. let 명령어
    3. 📌변수를 정수형으로 선언 declare -i iv
      1. 정수형 변수를 일반 변수에 저장하면 산술 결과 말고 문자열로 결과가 나옴
      2. 반대로 일반 변수의 연산결과를 정수형 변수에 저장하면 산술 연산이 적용
    • 비교 연산자
    • 논리 연산자
    • 비트 연산자
      • ~ : 비트 NOT연산자

        $ a=5
        $ b=12
        $ echo $((a|b))
        13
        => 그냥 a|b를 하면 문자열로 나오지만 (( )) 산술 확장을 이용해서 비트 연산자를 사용
    • 할당 연산자: 변수에 값을 저장하는 연산자
      • = 외에도 +=, _= , *=, ^= 등등을 사용할 수 있다
  • 서브스트링 확장
    변수에 저장된 문자열의 특정 부분을 추출하는 기능
    ⇒ 배열은 pass

  • 패턴 찾아 바꾸기

    • 가능한 형식
      • ${변수/패턴/문자열} : 변수의 문자열에서 패턴과 첫번째로 일치하는 문자나 문자열을 찾으면 지정한 문자열로 변경

      • ${변수//패턴/문자열} : 문자열에서 패턴과 일치하는 모든 문자나 문자열을 지정한 문자열로 변경

      • ${변수/#패턴/문자열} : 변수의 문자열 시작에서 패턴과 일치하는 문자나 문자열을 찾아 지정한 문자열로 변경

        ⇒ 일치하는 부분이 문자열의 시작이 아니면 변경 x

      • ${변수/%패턴/문자열} : 변수의 문자열 끝에서 패턴과 일치하는 문자나 문자열을 찾아 지정한 문자열로 변경

        사용 예시

        $ music="do re mi re do do do"
        cho ${music/re/Re}
        do Re mi re do do do
        $ echo ${music//re/Re}
        do Re mi Re do do do
        $ echo ${music/#re/Re}
        do re mi re do do do
        $ echo ${music/#do/DO~~}
        DO~~ re mi re do do do
        $ echo ${music/%do/DO~~}
        do re mi re do do DO~~
  • 대소문자 바꾸기

    • ${변수^^패턴} : 패턴과 일치하는 문자를 모두 대문자로 변경
    • ${변수^패턴} : 첫번째 문자가 패턴과 일치하면 첫번째 문자를 대문자로
      • 두 문자 이상은 패턴으로 검색 x
    • ${변수,,패턴} : 변수에 저장된 문자열에서 패턴과 일치하는 문자를 모두 소문자로 변환
    • ${변수,패턴} : 변수의 첫번째 문자가 패턴과 일치하면 첫번째 문자를 소문자로 변환
  • 변수 값에 따른 확장

    • ${변수:-문자열} : 변수에 값이 설정되지 않았거나 빈 값일때 지정한 문자열을 사용하게 하는 방법
    • ${변수:=문자열} : 문자열을 변수에 저장하면서 사용
    • ${변수:?문자열} : 변수가 빈 값일 때 에러 발생
    • 빈 값이 아닐 때 지정한 값 사용하기 : ${변수:+문자열}
  • 간접 확장

    • ${!변수} : 이름이나 값 동적 처리 가능. 약간 포인터처럼 사용 가능
  • 일치하는 패턴 제거

    • ${변수#패턴} : 가장 짧게 일치하는 문자열 제거
    • ${변수##패턴} : 가장 길게 일치하는 문자열 제거
    • ${변수%패턴} : 뒤에서 패턴을 검색해 가장 짧게 일치하는 문자열 제거
    • ${변수%%패턴} : 뒤에서 패턴을 검색해 가장 길게 일치하는 문자열 제거.
      ⇒모든 문자를 의미하는 *를 패턴에 종종 사용한다.

이처럼 Shell에서 사용하는 확장에 대해서 자세하게 알아보는 시간을 가졌습니다!


🛃.bashrc 파일을 이용한 개인화

  • bashrc ❔ 사용자 별로 관리하는 파일 ⇒ 사용자의 홈 디렉토리에 위치한다.

    • source 명령어를 사용해서 .bashrc 파일을 읽어들인다.
    • 역할
      • 다른 파일을 읽어들인다.
      • 변수를 설정한다.
      • alias를 설정한다.
      • Bash shell option을 설정한다.
    • $source 파일이름[인자]
  • $ bash command

    • 새로운 쉘 세션 시작( 서브쉘 생성) 현재 쉘 위에 쉘이 하나 더 겹쳐서 생성이 된다.
    • 환경 및 설정 분리 : 새로운 쉘에서 환경변수를 변경하거나 alias를 설정하거나 cd 명령어로 디렉토리 이동 하는 작업 → 새로 시작된 쉘 내부에서만 유효
    • exit / ctrl + d 로 빠져나올 수 있다.
  • .profile

    cat .profile
    # ~/.profile: executed by the command interpreter for login shells.
    # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
    # exists.
    # see /usr/share/doc/bash/examples/startup-files for examples.
    # the files are located in the bash-doc package.
    
    # the default umask is set in /etc/profile; for setting the umask
    # for ssh logins, install and configure the libpam-umask package.
    #umask 022
    
    # if running bash
    if [ -n "$BASH_VERSION" ]; then
        # include .bashrc if it exists
        if [ -f "$HOME/.bashrc" ]; then
    	. "$HOME/.bashrc"
        fi
    fi

    ===>> profile이 .bashrc 파일을 실행한다.

  • alias : 별명 => 명령어를 원하는 이름으로 별명을 추가할 수 있다.

    $ cat .bash_aliases  # 작성한 파일
    alias pss='ps -elf'
    
    $ source .bash_aliases # .bash 파일을 shell에 적용 
    $ pss                  #=> ps -elf 가 실행된다.
    
    $ alias                # 설정된 alias 확인
    alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
    .
    .
    alias ls='ls --color=auto'
    alias pss='ps -elf' #설정한 alias 확인 
    
    alias rm = 'rm -i' 
    #이렇게 설정하고  rm을 쓰면 rm -i command 실행 
    #그렇다면 그냥 rm을 쓰고 싶을 때는 어떻게 할 수 있을까?
    $\rm [file name] # => rm command가 실행된다. 
    

Library

라이브러리 타입

  1. 정적 라이브러리

    • libmylib.a
  2. 공유 라이브러리 === > 가장 많이 사용됨

    • libmylib.so
  3. 동적 라이브러리

    ar : archive 명령어
    ⇒ 라이브러리 생성
    ar r libmylib.a mylib.o ⇒ mylib.o라는 오브젝트 파일을 압축해서 정적 라이브러리로 만들어라!

    역할 : 여러 .o 파일을 하나의 .a 파일로 묶어 주는 도구
    옵션

    • r : replace
    • c : ceate → 이미 있어도 경고 없이 만들어라
    • s : symbol table 생성 → 링킹시 빨라짐

정적 라이브러리

# /exercise_lsp/06/10 
$ ls
lib  main.c  main.o  mylib.h
$ cd lib/
$ cat mylib.c 
int add(int a, int b)
{
    return a+b;
}
int sub(int a, int b)
{
    return a-b;
}
.
.
cc -o addsum main.o lib/mylib.o
=> link를 통해서 함수 사용 가능해짐

cc -o a main.c -Llib -lmylib -> lib 폴더 내에서  libmylib.a or libmylib.so를 찾는다.

정적 라이브러리는 관용적으로 앞에 lib를 붙여준다 ( 없을 시 못 찾음)

.a 의 확장자를 가짐

  1. $ ar r ⇒ 명령어로 라이브러리를 생성

  2. cc -o [실행파일 이름][src file] -L[lib Dir] -l[lib name]

    = = > 정적 라이브러리가 링킹 된 실행 파일 생성

    $ hi &
    [1] 16460
    
    $ pmap 16460 
    16460:   hi
    00005c1371256000      4K r---- hi  //.text
    . 
    00005c1371258000      4K r---- hi   //.rodata
    .
    00005c137125a000      4K rw--- hi  //.data + .bss
    00007bbd6b000000    160K r---- libc.so.6 // 동적 라이브러리 libc 각 섹션
    00007bbd6b028000   1620K r-x-- libc.so.6
    .
    00007bbd6b21c000     52K rw---   [ anon ]   //malloc /new로 할당한 힙 메모리 
    00007bbd6b234000     12K rw---   [ anon ]
    00007bbd6b262000      8K rw---   [ anon ]
    00007bbd6b264000      8K r---- ld-linux-x86-64.so.2
    .
    00007ffd40c38000    132K rw---   [ stack ]
    .
     total             2648K

    pmap ⇒ 지금 실행 중인 프로세스의 메모리 맵 전체이다.

  • 📌정적 라이브러리의 문제 : ⇒ 여러 프로세스에서 라이브러리를 사용할때 프로세스마다 라이브러리 할당 공간을 발생시킨다 ( 공간의 비효율성)]

    ⇒ 정적 라이브러리 링크 시에는 컴파일 할때 .a 안에 있는 오브젝트 파일들이 실행 파일 안에 통째로 들어간다. 따라서 런타임 시에 라이브러리를 로드 할 필요가 없음.

공유 라이브러리

개념 : Position Independent Code

  • 위치가 정해지면 안된다
    object file 생성

    cc -fPIC -c mylib.c
    PIC : position Independent code 

    공유 라이브러리 생성

    cc -shared -Wl,-soname=libmylib.so -o libmylib.so.1 mylib.o
    #각 option 설명 
    - shared :  오브젝트 파일을묶어서 동적 라이브러리 생성 옵션
    - wl,- :  뒤에 오는 옵션을 링커한테 그대로 전달 
    soname = [공유 라이브러리 이름] : 실행 파일 내에 이 프로그램은 해당 라이브러리가 필요하다고 기록
    -o libmylib.so.1 : 실제 디스크에 생성되는 파일 [기본 a.out]
    

    심볼릭 링크 연결

    ln -s libmylib.so.1  libmylib.so

    공유 라이브러리 사용하기

    $ cc -o main main.c -L./lib -lmylib
    $ main ====> error
    
    #해당 에러 발생 lib 파일 위치를 찾지를 못함 
    ./main: error while loading shared libraries: 
    libmylib.so: cannot open shared object file: No such file or directory
    ==> loader 에게 라이브러리 주소를 줘야한다.
    
    ===============================================
    $ldd main  # 실행파일이나 .so파일이 어떤 동적 라이브러리를 불러오는지를 출력
        linux-vdso.so.1 (0x00007ffc27fb5000)
        libmylib.so => not found
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000071fb71a00000)
        /lib64/ld-linux-x86-64.so.2 (0x000071fb71e34000)
    #어떤 라이브러리가 있는지 확인
    =>  libmylib.so의 위치를 찾지 못함
    
    #라이브러리 환경 변수 지정
    $ export LD_LIBRARY_PATH=lib
    이후
    $ main => 실행됨. 
    
    ===========================================
    make 를 활용한 build
    $ make
    cc    -c -o main.o main.c
    cc -o calc main.o -Llib -lmylib
    #자동으로 위의 명령어 실행 

    pmap을 이용한 점유 메모리 확인

    $ pmap 18015
    .
    .
    000075230e4f7000      4K r---- libprint.so.1
    000075230e4f8000      4K rw--- libprint.so.1
    000075230e4f9000      8K rw---   [ anon ]
    000075230e4fb000      8K r---- ld-linux-x86-64.so.2
    .
    .
    =>보면 실행 메모리에 libprint.so가 올라와있다.

    공유 라이브러리 VS 정적 라이브러리

    구분동적 링크 (Shared Library, .so)정적 링크 (Static Library, .a)
    실행 파일 크기작음 (보통 수십 KB ~ 수 MB)매우 큼 (libc 등까지 포함 시 수십 MB 이상이 일반적)
    pmap 출력실행 중인 프로세스의 메모리 맵에 사용된 공유 라이브러리 이름이 표시됨
    (예: libprint.so.1)
    공유 라이브러리 이름이 나타나지 않음
    실행 파일 섹션만 표시됨 → printf 같은 건 공유 lib
    메모리 사용 효율여러 프로세스가 동일한 공유 라이브러리를 사용할 경우, 코드 영역(.text)이 메모리 상에서 공유됨
    → 메모리 사용량 대폭 절감
    각 프로세스가 라이브러리 코드를 독립적으로 메모리에 적재

    → 동일한 코드라도 중복 로드되어 메모리 사용량 증가
    프로그램 시작 속도동적 링커가 실행 시점에 공유 라이브러리를 찾아서 로드해야 하므로 약간 느림모든 코드가 실행 파일에 포함되어 있어 즉시 실행 가능 → 시작 속도 빠름
    라이브러리 업데이트공유 라이브러리 파일만 교체하면, 재컴파일 없이 모든 프로그램에 즉시 반영
    (예: 보안 패치 적용 시 매우 유리)
    라이브러리 수정 시 실행 파일을 반드시 재컴파일 및 재배포해야 함
    ldd 명령어 결과의존하는 공유 라이브러리 목록이 상세히 출력됨not a dynamic executable 또는 statically linked 메시지 출력
    배포 및 의존성실행 환경에 해당 공유 라이브러리가 설치되어 있어야 함
    → 의존성 관리 필요
    단일 실행 파일로 모든 코드 포함
    → 외부 의존성 전무, 배포 간편
    주로 사용되는 상황시스템 라이브러리, 자주 업데이트되는 라이브러리, 메모리 효율이 중요한 서버/데스크톱 애플리케이션독립적인 배포가 필요한 경우 (Docker 이미지 최소화, 임베디드, 정적 빌드 환경 등)

동적 라이브러리

만들기 ==== > 공유 라이브러리와 같음 .

하지만 libmylib.so 사용법이 다르다

  • 동적 VS 공유 라이브러리

    { Body + libs} = = 정적

    {body } + { libs} == 공유 / 정적 →공통

    • 공유 라이브러리

      {body} === > {libs} 를 찾아서 끌고 올라옴 : loading 중 라이브러리를 못 찾을 수 있다

    • 동적 라이브러리

      {body} 실행 === > {libs 탐색 }: 탐색 시점을 실행시간에 동적으로 바꾼다. ==== > runtime load/unload 결정

code exam

/shell_Practice/exercise_lsp/06/30
$ cc -o calc main.c -ldl
$ ls
calc  main.c  _R.txt
$ calc
open error => 왜 에러가 나는가?
==============================
$ cat main.c |grep open
    handle = dlopen("libmylib.so", RTLD_NOW);
        printf("open error\n");
#파일을 살펴보면 라이브러리를 오픈해야하는데 라이브러리의 경로 에러.
$ echo $LD_LIBRARY_PATH 
lib
#아까 설정해놓은 PATH는 lib 하지만 현재 dir에 lib 디렉토리는 없다. => 에러 발생.
##그러면 경로를 어떻게 변경해야할까?
$ tree ..
..
├── 10
│   ├── a
│   ├── addsum
│   ├── lib
│   │   ├── libmylib.a
│   │   ├── mylib.c
│   │   └── mylib.o
│   ├── main.c
│   ├── main.o
│   └── mylib.h
├── 20
│   ├── calc
│   ├── lib
│   │   ├── libmylib.so -> libmylib.so.1
│   │   ├── libmylib.so.1
│   │   ├── makefile
│   │   ├── mylib.c
│   │   └── mylib.o
│   ├── main
│   ├── main.c
│   ├── main.o
│   ├── makefile
│   └── mylib.h
├── 30
│   ├── calc
│   ├── main.c
│   └── _R.txt
└── _L.txt

 🤩export LD_LIBRARY_PATH=../20/lib => 이렇게 export해주면 동적으로 라이브러리 load 성공
 ===========================Result 
 $ calc
add: 99

이것으로 7주차 3일간의 정리를 마치도록 하겠습니다.

.
.
.
추가적으로 금주에는 한화 비전 본사에서 목,금 양일간 직무 특강이 진행되었는데요!!!!

BSP, Edge Device Backend , PM , FE 등의 다양한 직무의 현업 지식을을 탐구할 수 있었습니다. 다음에 직무 특강 내용은 별도로 정리해서 올리도록 하겠습니다.

VEDA 파이탱~🥧

profile
세상의 어려운 문제를 해결하자

0개의 댓글