
12월이 벌써 다가왔습니다. 2025년도 어느덧 한달을 남겨두고 있는데요..
남은 2025년 열정을 불태우며 마무으리! 해보게쑵니다..
중괄호 확장 : { }를 사용해 문자열 시퀀스나 조합을 생성하는 것
$ 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가 출력된다
산술 연산이 가능한 경우
declare -i iv~ : 비트 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~~
대소문자 바꾸기
${변수^^패턴} : 패턴과 일치하는 문자를 모두 대문자로 변경${변수^패턴} : 첫번째 문자가 패턴과 일치하면 첫번째 문자를 대문자로${변수,,패턴} : 변수에 저장된 문자열에서 패턴과 일치하는 문자를 모두 소문자로 변환${변수,패턴} : 변수의 첫번째 문자가 패턴과 일치하면 첫번째 문자를 소문자로 변환변수 값에 따른 확장
${변수:-문자열} : 변수에 값이 설정되지 않았거나 빈 값일때 지정한 문자열을 사용하게 하는 방법${변수:=문자열} : 문자열을 변수에 저장하면서 사용${변수:?문자열} : 변수가 빈 값일 때 에러 발생${변수:+문자열}간접 확장
${!변수} : 이름이나 값 동적 처리 가능. 약간 포인터처럼 사용 가능일치하는 패턴 제거
${변수#패턴} : 가장 짧게 일치하는 문자열 제거${변수##패턴} : 가장 길게 일치하는 문자열 제거${변수%패턴} : 뒤에서 패턴을 검색해 가장 짧게 일치하는 문자열 제거${변수%%패턴} : 뒤에서 패턴을 검색해 가장 길게 일치하는 문자열 제거.이처럼 Shell에서 사용하는 확장에 대해서 자세하게 알아보는 시간을 가졌습니다!
bashrc ❔ 사용자 별로 관리하는 파일 ⇒ 사용자의 홈 디렉토리에 위치한다.
source 명령어를 사용해서 .bashrc 파일을 읽어들인다.$ bash command
.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가 실행된다.
라이브러리 타입
정적 라이브러리
공유 라이브러리 === > 가장 많이 사용됨
동적 라이브러리
ar : archive 명령어
⇒ 라이브러리 생성
ar r libmylib.a mylib.o ⇒ mylib.o라는 오브젝트 파일을 압축해서 정적 라이브러리로 만들어라!
역할 : 여러 .o 파일을 하나의 .a 파일로 묶어 주는 도구
옵션
# /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 의 확장자를 가짐
$ ar r ⇒ 명령어로 라이브러리를 생성
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가 올라와있다.
| 구분 | 동적 링크 (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 파이탱~🥧