업데이트(2018.03.16): 옵션 및 설명 추가

Linux 기반 운영체제에서 scp 명령어를 사용해서 로컬-원격 사이에 파일을 주고 받아보자.


환경 및 선수조건

  • Linux
  • Bash shell(/bin/bash)


scp 명령어

기본

  • scp: secure copy (remote file copy program)의 줄임말로 ssh를 이용해 네트워크로 연결된 호스트간에 파일을 주고 받는 명령어입니다.
  • 로컬 -> 리모트 (보내기), 리모트 -> 로컬 (가져오기)리모트 -> 리모트 (다른 호스트끼리 전송) 로 복사가 모두 가능합니다.
  • ssh를 이용하기 때문에 password를 입력하거나 ssh 키파일과 같은 identity file을 이용해 파일 송수신이 가능합니다.


기본 사용 문법

  • manual page에 있는 자료
scp [options ...] [source] [target]
  • 기본 형태
# Local -> Remote
scp 목적파일명(경로) 유저명@IP주소:목적디렉토리
# Remote -> Local
scp 유저명@IP주소:파일디렉토리 목적파일명(경로)
# Remote(source) -> Remote(target)
scp 유저명@IP주소:파일디렉토리 유저명@IP주소:파일디렉토리


옵션

  • -r: 재귀적으로 모든 폴더들을 복사합니다. 폴더를 복사할 때 사용하는 옵션으로 이때 전송하고자 하는 대상은 폴더로 지정하면 됩니다. 아래에 예제를 참고하시면 됩니다. symbolic link가 있는 경우에는 target에 symbolic link를 생성하지 않고 symbolic link가 가리키는 파일 혹은 폴더를 복사합니다.
  • -P: ssh 포트를 지정하는 옵션
  • -i: ssh 키파일과 같은 identity file의 경로를 지정하는 옵션
  • -v: verbose 모드로 상세내용을 보며 디버깅을 할 때 사용합니다.
  • -p: 파일의 수정 시간과 권한을 유지합니다.


예제

로컬 -> 리모트

  • 패스워드 사용하는 경우
scp ~/test.txt twpower@[IP주소]:/home/twpower
  • -i 옵션
  • identity file을 지정해서 사용할 때
scp -i ~/.ssh/twpower-private-server ~/test.txt twpower@[IP주소]:/home/twpower
  • -r 옵션
  • 폴더를 복사하는 경우
scp -r ~/test_folder/ twpower@[IP주소]:/home/twpower
  • -P 옵션
scp -P 22 ~/test.txt twpower@[IP주소]:/home/twpower


리모트 -> 로컬

  • 패스워드 사용하는 경우
scp twpower@[IP주소]:/home/twpower/test.txt /Users/taewoo
  • -i 옵션
  • identity file을 지정해서 사용할 때
scp -i ~/.ssh/twpower-private-server twpower@[IP주소]:/home/twpower/test.txt /Users/taewoo
  • -r 옵션
  • 폴더를 복사하는 경우
scp -r twpower@[IP주소]:/home/twpower/test_folder /Users/taewoo
  • -P 옵션
scp -P 22 twpower@[IP주소]:/home/twpower/test.txt /Users/taewoo


참고자료

업데이트(2019.01.19): 코드 수정 및 검증 코드 추가

C++에서 힙(Heap)을 구현해보자


환경

  • C++


Heap이란?

개념

  • Heap이란 완전 이진 트리의 일종으로 부모 노드와 자식 노드간에 항상 대소관계가 성립하는 자료구조를 의미합니다.
  • 아래의 사진을 보면 부모 노드가 자식 노드보다 항상 크며 이러한 구조를 최대힙(Max Heap)이라고 하고 그 반대를 최소힙(Min Heap)이라고 합니다.
  • 이 때 부모와 자식 노드의 대소관계만 중요하며 형제 노드들간에는 관계가 없습니다.
  • 이렇게 아래처럼 구현하고 위와 같은 속성(부모와 자식간에 대소관계)을 띄기 때문에 최상단 부모인 루트에는 항상 가장 크거나 작은 값이 오며 이를 이용해서 그 유명한 우선 순위 큐(Priority Queue)의 구현이 가능합니다.


구현

공통

  • 완전 이진 트리는 배열로 구현합니다.
  • 구현을 쉽게 하기 위해 배열을 사용할 때 인덱스는 1부터 사용합니다.
  • 특정 노드의 배열 인덱스가 current라고 한다면 부모 노드current / 2를 통해 찾아갈 수 있고 자식 노드current * 2(좌측 자식 노드) 또는 current * 2 + 1(우측 자식 노드)을 통해서 찾아갈 수 있습니다.
  • 현재 노드 인덱스: current
  • 부모 노드 인덱스: current / 2
  • 자식 노드들 인덱스 (순서 대로 좌우): current * 2, current * 2 + 1


삽입

  • 완전 이진 트리 가장 끝에 원소를 추가하고 추가한 부분의 원소와 해당 원소의 부모 노드와 크기를 비교하고 바꿔가면서 위치를 찾습니다.
void push(int data) {

	// 힙의 가장 끝에 데이터 추가
	heap[++heap_count] = data;

	// 아래의 과정은 child를 parent와 비교하면서 알맞은 위치로 하나씩 올리는 부분
	int child = heap_count;
	int parent = child / 2;
	while (child > 1 && heap[parent] < heap[child]) {
		swap(&heap[parent], &heap[child]);
		child = parent;
		parent = child / 2;
	}

}


삭제

  • 힙의 가장 첫번째 원소를 반환하고 첫번째 위치에 힙의 가장 끝 원소를 대입합니다.
  • 첫번째 원소를 자식과 계속 비교하고 값을 바꿔가면서 힙을 재정렬합니다.
  • 이 때, 자식은 왼쪽과 오른쪽 2개가 생기기 때문에 최대힙을 구현하는 경우에는 더 큰 자식과 값을 바꿉니다.(최소힙일 때는 그 반대!)
int pop() {

	// 힙의 가장 첫번째 원소를 반환
	// 힙의 가장 앞만 보고 있다!
	int result = heap[1];

	// 첫번째 원소를 힙의 가장 끝에 원소와 바꾸고
	// 가장 끝은 이제 쓰지 않을 예정이니 heap_count를 내려준다.
	swap(&heap[1], &heap[heap_count]);
	heap_count--;

	// 아래의 과정은 child를 parent와 비교하면서 알맞은 위치로 하나씩 내리는 부분
	int parent = 1;
	int child = parent * 2;
	if (child + 1 <= heap_count) {
		child = (heap[child] > heap[child + 1]) ? child : child + 1;
	}

	while (child <= heap_count && heap[parent] < heap[child]) {
		swap(&heap[parent], &heap[child]);

		parent = child;
		child = child * 2;
		if (child + 1 <= heap_count) {
			child = (heap[child] > heap[child + 1]) ? child : child + 1;
		}
	}

	return result;
}


코드

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define HEAP_SIZE 256
#define ARRAY_SIZE 10

// Max Heap 구현
// 구현을 쉽게 하기 위해서 값들은 모두 양수라고 가정!
// 배열에서 값 0은 비어있음을 의미한다고 가정하자!
// heap은 배열의 인덱스가 1부터 시작합니다!

int heap[HEAP_SIZE]; // max heap
int heap_count = 0; // heap의 원소의 갯수를 나타냄과 동시에 배열의 가장 끝 원소를 나타내며 heap의 끝을 나타내기도 합니다.

void swap(int * a, int * b) {
	int tmp = *a; *a = *b; *b = tmp;
}

void init() {
	heap_count = 0;
}

int size() {
	return heap_count;
}

void push(int data) {

	// 힙의 가장 끝에 데이터 추가
	heap[++heap_count] = data;

	// 아래의 과정은 child를 parent와 비교하면서 알맞은 위치로 하나씩 올리는 부분
	int child = heap_count;
	int parent = child / 2;
	while (child > 1 && heap[parent] < heap[child]) {
		swap(&heap[parent], &heap[child]);
		child = parent;
		parent = child / 2;
	}

}

int pop() {

	// 힙의 가장 첫번째 원소를 반환
	// 힙의 가장 앞만 보고 있다!
	int result = heap[1];

	// 첫번째 원소를 힙의 가장 끝에 원소와 바꾸고
	// 가장 끝은 이제 쓰지 않을 예정이니 heap_count를 내려준다.
	swap(&heap[1], &heap[heap_count]);
	heap_count--;

	// 아래의 과정은 child를 parent와 비교하면서 알맞은 위치로 하나씩 내리는 부분
	int parent = 1;
	int child = parent * 2;
	if (child + 1 <= heap_count) {
		child = (heap[child] > heap[child + 1]) ? child : child + 1;
	}

	while (child <= heap_count && heap[parent] < heap[child]) {
		swap(&heap[parent], &heap[child]);

		parent = child;
		child = child * 2;
		if (child + 1 <= heap_count) {
			child = (heap[child] > heap[child + 1]) ? child : child + 1;
		}
	}

	return result;
}

int main() {

	int arr[ARRAY_SIZE];

	// 랜덤함수를 위한 srand와 seed
	srand(time(NULL));

	// 배열 초기화
	for (int i = 0; i < ARRAY_SIZE; i++) {
		// 1 ~ 50까지의 난수 생성
		arr[i] = rand() % 50 + 1;
	}

	// 삽입
	for (int i = 0; i < ARRAY_SIZE; i++) {
		push(arr[i]);
	}

	// pop 하면서 값들 하나씩 확인
	// Max Heap이기 때문에 값들이 내림차순으로 정렬됨 -> Heap Sort
	for (int i = 0; i < ARRAY_SIZE; i++) {
		printf("%d ", pop());
	}
	printf("\n");

	return 0;
}


검증

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <algorithm>
#include <iostream>
#include <functional>

#define HEAP_SIZE 256
#define TOTAL_TEST_CASE 100
#define TEST_ARRAY_SIZE 20

using namespace std;

int heap[HEAP_SIZE];
int heap_count = 0;

void swap(int * a, int * b) {
	int tmp = *a; *a = *b; *b = tmp;
}

void init() {
	heap_count = 0;
}

int size() {
	return heap_count;
}

void push(int data) {

	// 힙의 가장 끝에 데이터 추가
	heap[++heap_count] = data;

	// 아래의 과정은 child를 parent와 비교하면서 알맞은 위치로 하나씩 올리는 부분
	int child = heap_count;
	int parent = child / 2;
	while (child > 1 && heap[parent] < heap[child]) {
		swap(&heap[parent], &heap[child]);
		child = parent;
		parent = child / 2;
	}

}

int pop() {

	// 힙의 가장 첫번째 원소를 반환
	// 힙의 가장 앞만 보고 있다!
	int result = heap[1];

	// 첫번째 원소를 힙의 가장 끝에 원소와 바꾸고
	// 가장 끝은 이제 쓰지 않을 예정이니 heap_count를 내려준다.
	swap(&heap[1], &heap[heap_count]);
	heap_count--;

	// 아래의 과정은 child를 parent와 비교하면서 알맞은 위치로 하나씩 내리는 부분
	int parent = 1;
	int child = parent * 2;
	if (child + 1 <= heap_count) {
		child = (heap[child] > heap[child + 1]) ? child : child + 1;
	}

	while (child <= heap_count && heap[parent] < heap[child]) {
		swap(&heap[parent], &heap[child]);

		parent = child;
		child = child * 2;
		if (child + 1 <= heap_count) {
			child = (heap[child] > heap[child + 1]) ? child : child + 1;
		}
	}

	return result;
}

int main() {

	int arr[TEST_ARRAY_SIZE]; // heap에 이용할 자료들
	int ans_arr[TEST_ARRAY_SIZE]; // 검증에 사용할 자료들

	srand(time(NULL));

	int test_case;
	int correct = 0;

	for (test_case = 1; test_case <= TOTAL_TEST_CASE; ++test_case) {

		// 같은지 확인하는 변수
		bool is_equal = true;

		// 자료들 입력
		for (int i = 0; i < TEST_ARRAY_SIZE; i++) {
			arr[i] = rand() % 2000 + 1; // 1 ~ 2000 사이의 난수 생성
			ans_arr[i] = arr[i];
		}

		// heap 정렬
		for (int i = 0; i < TEST_ARRAY_SIZE; i++) {
			push(arr[i]);
		}
		for (int i = 0; i < TEST_ARRAY_SIZE; i++) {
			arr[i] = pop();
		}

		// 정답 생성
		// greater<int>()는 내림차순을 위해서 사용
		// sort(ans_arr, ans_arr+TEST_ARRAY_SIZE)만 사용하면 오름차순이 됨
		sort(ans_arr, ans_arr + TEST_ARRAY_SIZE, greater<int>());

		// 정답과 힙정렬 결과 비교
		for (int i = 0; i < TEST_ARRAY_SIZE; i++) {
			if (ans_arr[i] != arr[i]) {
				is_equal = false;
				break;
			}
		}

		if (is_equal) correct++;

	}

	printf("Total: %d / %d\n", correct, TOTAL_TEST_CASE);

	return 0;
}


참고자료

업데이트(2019.02.03): 코드 일부 수정 및 개선

C++에서 단순 열결 리스트(Singly Linked List)를 구현해보자


환경

  • C++


Singly Linked List란?

개념

  • 아래처럼 하나의 노드에 필요한 정보를 담고 다음에 해당하는 노드를 가리키고 있는 자료구조로 포인터를 이용해 자료들을 선형으로 연결할 자료구조이다.
  • 배열과 비교했을 때 추가 및 삭제가 쉽다는 장점이 있지만 접근할 때 O(n)만큼 걸린다는 단점이 있습니다.



구현

공통

  • 구현을 편리하게 하기위해 전역으로 하나의 리스트만 만들었습니다.
  • 큰 틀은 아래와 같으면 추가, 삭제 그리고 순회의 경우에 필요한 부분들을 수정하면 됩니다.
  • list는 리스트의 처음을 가리킵니다.
#include <stdio.h>
#include <stdlib.h>

// Node
struct Node {
	int data;
	Node * next;
};

// Global list
Node * list;


추가/삭제 공통

  • 추가와 삭제의 경우에 첫번째 노드인지 아닌지를 고려해주면 구현이 편합니다.
  • 리스트의 중간에서 자료의 추가나 제거가 이루어질 때 현재 노드를 가리키는 cur와 이전 노드를 가리키는 prev가 있으면 추가 및 삭제가 편합니다.
  • 삭제의 경우에 삭제하고자 하는 노드가 있으면 true를 반환하고 없다면 false를 반환합니다.
  • 함수 ascending_order_add의 경우에는 오름차순으로 리스트를 생성하는 예제 함수입니다.


추가

  • 아래처럼 추가하려는 노드의 위치를 찾은 후에 새 노드의 next를 다음 노드를 가리키고 이전 노드가 추가하려는 노드를 가리키게 합니다.
  • 코드는 크게 3가지 방식이 있습니다.
  • add: 새로 추가하는 방법
  • ascending_order_add: 중간에 추가하는 방법
  • add_unique: 중복된 값 없이 추가하는 방법



// Add - one by one
void add(int key) {

	Node * new_node = (Node*)malloc(sizeof(Node));
	new_node->data = key;
	new_node->next = NULL;

	// Check first element
	if (list == NULL) {
		list = new_node;
	}
	else {
		// Add new node to head
		new_node->next = list;
		list = new_node;
	}
}
// Add - add ascending order
void ascending_order_add(int key) {

	Node * new_node = (Node*)malloc(sizeof(Node));
	new_node->data = key;
	new_node->next = NULL;

	if (list == NULL) {
		list = new_node;
	}
	else {

		Node * cur = list;
		Node * prev = NULL;

		// If first element is larger than key
		if (cur->data > new_node->data) {
			new_node->next = cur;
			list = new_node;
		}
		// Other cases
		else {
			while (cur != NULL && cur->data < new_node->data) {
				prev = cur;
				cur = cur->next;
			}
			// Add in middle
			if (cur != NULL) {
				new_node->next = cur;
				prev->next = new_node;
			}
			// Add to end
			else {
				prev->next = new_node;
			}
		}
	}
}
// Add - add only unique value
void add_unique(int key) {
	Node * new_node = (Node*)malloc(sizeof(Node));
	new_node->data = key;
	new_node->next = NULL;

	if (list == NULL) {
		list = new_node;
	}
	else {
		Node * cur = list;

		// Duplication check
		while (cur != NULL) {
			if (cur->data == key) {
				return;
			}
			cur = cur->next;
		}

		new_node->next = list;
		list = new_node;
	}
}


삭제

  • 아래처럼 삭제하려는 노드의 위치를 찾은 후에 이전노드가 삭제하려는 노드의 다음 노드를 가리키도록 하면 됩니다.
  • 똑같이 처음을 주의해주고 쉽게 구현하기 위해 curprev을 이용합니다.



// Remove
bool remove(int key) {

	if (list == NULL) {
		return false;
	}

	if (list->data == key) {
		Node * cur = list;
		list = list->next;
		free(cur);
		return true;
	}
	else {
		Node * cur = list->next;
		Node * prev = list;
		while (cur != NULL && cur->data != key) {
			prev = cur;
			cur = cur->next;
		}

		if (cur == NULL) return false;

		prev->next = cur->next;
		free(cur);
		return true;
	}
}


코드

#include <stdio.h>
#include <stdlib.h>

// Node
struct Node {
	int data;
	Node * next;
};

// Global list
Node * list;

// Init
void init() {

	if (list == NULL) {
		return;
	}
	else {
		Node * cur;
		cur = list;

		while (cur != NULL) {
			list = cur->next;
			free(cur);
			cur = list;
		}
	}
}

// Add - one by one
void add(int key) {

	Node * new_node = (Node*)malloc(sizeof(Node));
	new_node->data = key;
	new_node->next = NULL;

	// Check first element
	if (list == NULL) {
		list = new_node;
	}
	else {
		// Add new node to head
		new_node->next = list;
		list = new_node;
	}
}

// Add - add ascending order
void ascending_order_add(int key) {

	Node * new_node = (Node*)malloc(sizeof(Node));
	new_node->data = key;
	new_node->next = NULL;

	if (list == NULL) {
		list = new_node;
	}
	else {

		Node * cur = list;
		Node * prev = NULL;

		// If first element is larger than key
		if (cur->data > new_node->data) {
			new_node->next = cur;
			list = new_node;
		}
		// Other cases
		else {
			while (cur != NULL && cur->data < new_node->data) {
				prev = cur;
				cur = cur->next;
			}
			// Add in middle
			if (cur != NULL) {
				new_node->next = cur;
				prev->next = new_node;
			}
			// Add to end
			else {
				prev->next = new_node;
			}
		}
	}
}

// Add - add only unique value
void add_unique(int key) {
	Node * new_node = (Node*)malloc(sizeof(Node));
	new_node->data = key;
	new_node->next = NULL;

	if (list == NULL) {
		list = new_node;
	}
	else {
		Node * cur = list;

		// Duplication check
		while (cur != NULL) {
			if (cur->data == key) {
				return;
			}
			cur = cur->next;
		}

		new_node->next = list;
		list = new_node;
	}
}

// Remove
bool remove(int key) {

	if (list == NULL) {
		return false;
	}

	if (list->data == key) {
		Node * cur = list;
		list = list->next;
		free(cur);
		return true;
	}
	else {
		Node * cur = list->next;
		Node * prev = list;
		while (cur != NULL && cur->data != key) {
			prev = cur;
			cur = cur->next;
		}

		if (cur == NULL) return false;

		prev->next = cur->next;
		free(cur);
		return true;
	}
}

// Traverse
void traverse() {

	Node * cur = list;
	while (cur != NULL) {
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");

}

int main() {

	int arr[9] = { 2, 4, 6, 8, 1, 3, 5, 7, 9 };
	int arr_duplicated[18] = { 8, 1, 3, 2, 4, 6, 8, 1, 3, 5, 7, 9, 2, 4, 6, 5, 7, 9 };
	int arr_rmv[4] = { 2, 9, 8, 100 };


	// Add to list 1
	init();
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) {
		add(arr[i]);
	}
	printf("After add(normal): ");
	traverse();


	// Add to list 2
	init();
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) {
		ascending_order_add(arr[i]);
	}
	printf("After add(ascending): ");
	traverse();


	// Add to list 3
	init();
	for (int i = 0; i < sizeof(arr_duplicated) / sizeof(arr_duplicated[0]); ++i) {
		add_unique(arr_duplicated[i]);
	}
	printf("After add(unique): ");
	traverse();


	// Remove specific values in list
	for (int i = 0; i < sizeof(arr_rmv) / sizeof(arr_rmv[0]); ++i) {
		remove(arr_rmv[i]);
	}
	printf("After remove: ");
	traverse();

	return 0;

}

실행결과

After add(normal): 9 7 5 3 1 8 6 4 2
After add(ascending): 1 2 3 4 5 6 7 8 9
After add(unique): 9 7 5 6 4 2 3 1 8
After remove: 7 5 6 4 3 1


참고자료

Linux 기반 운영체제에서 tee 명령어를 사용해 화면과 파일에 동시에 출력해보자


환경 및 선수조건

  • Linux
  • Bash shell(/bin/bash)


tee 명령어

  • tee 명령어는 다음 아래 사진처럼 명령어의 출력 결과를 파일과 화면에 동시에 출력할 수 있도록 해주는 명령어입니다.
  • stdin을 받아서 stdout과 하나 이상의 파일에 그 입력을 출력하는겁니다.

기본 사용법

  • [ -a ]: 덮어쓰기 말고 해당 파일에 추가해서 입력합니다.
  • [ -i ]: interrupt를 무시하는 옵션
  • [ File ... ]: 파일들 이름입니다.

tee [ -a ] [ -i ] [ File ... ]


예제 - 명령어의 결과를 파일과 stdout으로 출력하기

$ echo test | tee tee-test-file.txt
test
$ cat tee-test-file.txt
test


예제 - shell에서 파일 생성하기

$ tee tee-test-file.txt << EOF
> Multi line test
> 1
> 2
> 3
> End!
> EOF
Multi line test
1
2
3
End!
$ cat tee-test-file.txt
Multi line test
1
2
3
End!


참고자료

쉘 스크립트에서 함수나 스크립트의 실행결과를 받아보자


환경 및 선수조건

  • Linux 기반 시스템에 대한 이해
  • Bash shell(/bin/bash)의 사용법


Shell에서의 반환값?

Shell Script에서의 값 반환

  • 일반적으로 shell script에서는 우리가 아는 컴퓨터 언어에서의 return 반환값이 없습니다.
  • shell script가 실행되는 프로세스에서 exit을 통해 상태 종료 표시만을 프로세스 실행 결과로 반환할 수 있습니다.
  • 일반적으로 0은 성공을 나타내며 나머지인 1 ~ 255는 에러를 나타냅니다.


exit의 예시 확인

  • 간단하게 예시를 확인해 보겠습니다.
  • 아래처럼 없는 명령어를 아무거나 입력하고 실행해서 오류가 떴음을 확인하고 $?를 통해서 방금 명령어에 대한 exit code를 확인합니다.
  • $?는 방금 실행된 프로세스가 반환한 결과값을 저장하고 있습니다.
$ error_command
error_command: command not found
$ echo $?
127


Shell 스크립트 함수에서 결과값 받기

  • 일반적인 언어처럼 return과 같은 결과를 얻고 싶을 때는 2가지 방법을 사용할 수 있습니다.
  • $(명령어 or 쉘 스크립트 실행 or 쉘 스크립트 함수)와 같이 $()안에 명령어, 쉘 스크립트 또는 쉘 스크립트 함수를 넣으면 해당 부분들을(명령어, 쉘 스크립트 또는 쉘 스크립트 함수) 실행할 subshell을 호출합니다.
  • 해당 $()를 통한 subshell 생성은 부모 shell의 변수나 값들을 가져오기 때문에 함수도 변수도 다 사용할 수 있습니다. 다만, subshell의 결과가 부모 shell에 영향을 주지는 않습니다.
  • subshell을 호출하지만 $$를 통해서 PID를 출력하면 parent shell의 프로세스 아이디를 호출합니다.


(방법1) echo를 통해서 값 전달 받기

  • 다음 아래처럼 subshell로 함수나 명령어를 실행해서 결과를 가져올 수 있습니다.
#!/bin/bash

get_result_func () {
	test=123456
	# echo 함수를 통해서 결과를 전달
	# return "Result is ${test}"라고 생각하시면 됩니다.
	echo "Result is ${test}"
}

# 다음 아래와 같이 함수 호출의 결과를 변수에 받습니다.
ret_value=$(get_result_func)

echo $ret_value
$ ./shell_script_practice.sh
Result is 123456


(방법2) 변수 공유하기

  • 다음처럼 변수를 전역으로 선언하고 해당 변수를 이용해서 사용할 수 있습니다.
#!/bin/bash

ret_value=""

get_result_func () {
	# Do Something
	ret_value="aaaaaaaaa"
}

get_result_func
echo $ret_value
$ ./shell_script_practice.sh
aaaaaaaaa


참고자료