리눅스 스크립트 작성 공부 겸, GOLDILOCKS 온라인 백업 테스트 겸 스크립트를 작성해 보았습니다.
먼저 전체 소스및 알고리즘을 확인한 뒤에, 차근차근 짚어보도록 하겠습니다.
소스 알고리즘
1. 백업 스크립트가 현재 수행중인지 확인합니다.
- 수행중이라면 백업 스크립트 종료
2. 옵션으로 받은 인자를 확인합니다.
- 옵션이 적절치 않다면 스크립트 종료
3. 입력받은 아이디 비밀번호로 데이터베이스 접속을 시도합니다.
- 접속 실패시 스크립트 종료
4. 입력받은 아이디가 백업 권한이 있는지 확인합니다.
- 권한 없을시 스크립트 종료
5. 데이터베이스 버전을 확인합니다.
- StandAlone 혹은 Cluster
6. 백업모드를 시작합니다.
- 백업모드 시작 실패시 백업모드 종료 후 스크립트 종료
7. 백업에 필요한 파일을 데이터베이스로 메타정보로부터 가져옵니다.
- 데이터 반환 실패시 백업모드 종료 후 스크립트 종료
8. 물리적 디스크 공간을 확인합니다.
- 백업에 필요한 파일 크기보다 물리적 디스크 공간이 부족한 경우 백업모드 종료 후 스크립트 종료
9. 파일을 백업경로에 복사합니다.
- 복사 실패 시 백업모드 종료 후 스크립트 종료
10. 백업을 종료합니다.
- 백업모드 실패시 루프
전체 소스 확인하기
차근차근 짚어가기
0. 시작 전 초기변수 할당
file_path=$(readlink -f "$0") folder_path=$(dirname "${file_path}") today=$(date '+%Y%m%d_%H%M%S') backup_folder="${folder_path}/${today}" info="[INFORMATION]" fatal="[FATAL] "
readlink -f 로 파일명을 포함한 현재 경로를 읽어와 file_path 변수에 저장합니다.
dirname 으로 파일명을 제외한 현재 경로를 읽어와 folder_path 변수에 저장합니다.
현재시간을 today 변수에 저장합니다.
만약 옵션값을 지정하지 않는다면 folder_path/today 변수값이 백업 경로가 될 것입니다.
정보성과 실패성 로그의 변수를 지정합니다.
help() { echo "" echo "Usage" echo " $ sh goldilocks_backup.sh user_name password" echo " $ sh goldilocks_backup.sh [OPTIONS] user_name password" echo "" echo "arguments:" echo " user_name user name" echo " password password" echo "" echo "options:" echo " -h Print Help Messages" echo " -m [i|h|c] Set Backup Mode (Default : h) [ ONLINE : Incremental (i), Full (h) ][ OFFLINE : Full (c) ]" echo " -p PATH Set Absolute Destination Path (Default : current path)" exit 0 } while getopts "m:p:h" opt do case $opt in m) mode=$OPTARG ;; p) path=$OPTARG ;; h) help ;; ?) help ;; esac done if [[ "${mode}" == "" ]] then mode="h" fi if [[ "${path}" == "" ]] then path=${folder_path} fi shift $(( $OPTIND - 1)) user_id=$1 user_pw=$2
getopts 함수로 현재 옵션들의 값을 설정합니다.
만약 옵션이 부적절한 경우 help 란의 내용을 출력합니다.
shift 명령어를 사용하여 옵션 뒤에 나오는 아이디와 비밀번호를 할당합니다.
1. 백업 스크립트가 현재 수행중인지 확인합니다.
pline=`ps -ef | grep "goldilocks_backup.sh" | grep -v "grep" | grep -v "$$" | wc -l` if [[ $pline -ne 0 ]] then Logging "${fatal}" "Goldilocks Backup Script is Already Started" exit 0; fi
$$ 는 현재 스크립트의 pid 를 반환합니다.
전체 프로세스 목록의 스크립트 파일명 중 현재 수행한 파일의 프로세스를 제외합니다.
이 때의 라인수가 0이 아니라면 다른 프로세스가 돌고 있다는 의미이므로 실패합니다.
2. 옵션으로 받은 인자를 확인합니다.
function Chk_argu { if [[ "${user_id}" == "" ]] then Logging "${fatal}" "UserID is invalid." help exit 0 fi if [[ "${user_pw}" == "" ]] then Logging "${fatal}" "UserPW is invalid." help exit 0 fi if [[ ! -d "${path}" ]] then Logging "${fatal}" "Path is invalid." help exit 0 fi if [[ "${mode}" == "h" ]] || [[ "${mode}" == "i" ]] || [[ "${mode}" == "c" ]] then Logging "${info}" "GOLDILOCKS BACKUP START" else Logging "${fatal}" "Mode is invalid." help exit 0 fi session="gsql ${user_id} ${user_pw} --no-prompt" Logging "${info}" "START TIME = ${today}" Logging "${info}" "BACKUP MODE = ${mode}" Logging "${info}" "BACKUP PATH = ${path}" Logging "${info}" "USER ID = ${user_id}" #Logging "${info}" "USER PW = ${user_pw}" }
옵션값이 잘못되어 있는 경우, 로그와 함께 스크립트를 종료합니다.
그렇지 않다면, 백업 시작전 정보를 로깅합니다.
3. 입력받은 아이디 비밀번호로 데이터베이스 접속을 시도합니다.
function Chk_Session { $session << EOF quit EOF }
db_session=`Chk_Session | grep "ERR-"` if [[ "${db_session}" != "" ]] then Logging "${fatal}" "${db_session}" exit 0 fi
데이터베이스로 접속을 시도해봅니다.
실패 시, 로그와 함께 스크립트를 종료합니다.
4. 입력받은 아이디가 백업 권한이 있는지 확인합니다.
function Chk_Grant_before_backup { # Alter Database 권한 $session << EOF set linesize 1024 set pagesize 10000 set timing off SELECT '@grant_success' AS CHK FROM DBA_DB_PRIVS WHERE GRANTEE=(SELECT USER FROM DUAL) AND PRIVILEGE = 'ALTER DATABASE'; quit EOF }
db_grant=`Chk_Grant_before_backup | grep "^@"` if [[ "${db_grant}" == "" ]] then Logging "${fatal}" "ERR-42000(16210): lacks privilege (ALTER DATABASE ON DATABASE)" exit 0 fi
권한이 없는 경우 로그와 함께 스크립트를 종료합니다.
에러시 에러결과를 함수로부터 받아오는게 아니라 강제로 작성하여 넣은건 좀 그렇지만 우선 넣었습니다.
5. 데이터베이스 버전을 확인합니다.
function Chk_DBName { $session << EOF set linesize 1024 set pagesize 10000 set timing off SELECT '@' || NVL(CLUSTER_MEMBER_NAME, 'STANDALONE') AS CHK FROM DUAL; quit EOF }
db_name=`Chk_DBName | grep "^@" | sed 's/ //g' | cut -d '@' -f2` if [[ "${db_name}" != "" ]] then Logging "${info}" "DB NAME = ${db_name}" else Logging "${fatal}" "DB NAME = ${db_name}" exit 0 fi
클러스터인 경우 멤버명을, 단일인 경우 STANDALONE 을 반환합니다.
실패한 경우 로그와 함께 스크립트를 종료합니다.
6. 백업모드를 시작합니다.
function Chk_BeginBackup { if [[ "${db_name}" == "STANDALONE" ]] then $session << EOF set linesize 1024 set pagesize 10000 set timing off ALTER DATABASE BEGIN BACKUP; quit EOF else $session << EOF set linesize 1024 set pagesize 10000 set timing off ALTER DATABASE BEGIN BACKUP AT ${db_name}; quit EOF fi }
db_sbackup=`Chk_BeginBackup` db_sbackup=`echo ${db_sbackup} | sed 's/\n//g'` if [[ ${db_sbackup} == *"ERR-"* ]] then Logging "${info}" "ALTER DATABASE BEGIN BACKUP AT ${db_name}" Logging "${fatal}" "${db_sbackup}" exit 0 else Logging "${info}" "ALTER DATABASE BEGIN BACKUP AT ${db_name}" Logging "${info}" "${db_sbackup}" fi
클러스터인 경우 AT 절로 접속한 데이터베이스만 백업모드로 변경합니다.
실패한 경우 로그와 함께 스크립트를 종료합니다.
7. 백업에 필요한 파일을 데이터베이스로 메타정보로부터 가져옵니다.
function Chk_DBFile_before_backup { # V$DB_FILE $session << EOF set linesize 1024 set pagesize 10000 set timing off SELECT '@' || FILE_NAME AS CHK FROM V\$DB_FILE; quit EOF }
db_file=`Chk_DBFile_before_backup | grep "^@" | sed 's/ //g'` if [[ ${db_file} == *"ERR-"* ]] then Logging "${fatal}" "${db_file}" Chk_EndBackup2 Logging "${fatal}" "Backup Failure." exit 0 fi
데이터베이스로부터 백업에 필요한 파일을 가져옵니다.
실패한 경우 백업 모드 종료 후 로그와 함께 스크립트를 종료합니다.
8. 물리적 디스크 공간을 확인합니다.
9. 파일을 백업경로에 복사합니다.
function Chk_Space_before_backup { # DB Size vs FileSystem Size backup_space=`echo ${path} | df -k | tail -1 | awk '{print $4*1024}'` Logging "${info}" "${path} is available size ${backup_space} Bytes" i=0 each_file_sumsize=0 while [[ "${db_file}" != "" ]] do db_file=${db_file#*@} each_file[$i]=`echo ${db_file} | cut -d'@' -f1 | sed 's/ //g'` if [[ -f "${each_file[$i]}" ]] then each_file_size=`ls -al ${each_file[$i]} | awk '{print $5}'` each_file_sumsize=`expr ${each_file_sumsize} + ${each_file_size}` Logging "${info}" "${each_file[$i]} size is ${each_file_size} Bytes" else Logging "${info}" "${each_file[$i]} does not exist" fi if [[ "${each_file_sumsize}" -ge "${backup_space}" ]] then Logging "${fatal}" "Backup Size is greater than ${each_file_sumsize} Bytes. It requires more Available Bytes on disk" Chk_EndBackup2 Logging "${fatal}" "Backup Failure." exit 0; fi if [[ "${db_file}" == "${each_file[$i]}" ]] then break; fi i=`expr $i + 1` done state=0 while [[ $i -ge 0 ]] do location_file="location.ctl" from_file=`echo "${each_file[$i]}" | sed 's/\/\//\//g'` to_file=`echo "${path}/${today}/${from_file%/*}" | sed 's/\/\//\//g'` if [[ ! -d "${to_file}" ]] then mkdir -p ${to_file} fi location_file=${from_file%/*}/${location_file} if [[ -f "${location_file}" ]] && [[ $state -eq 0 ]] then cp ${location_file} ${to_file} if [[ $? -eq 0 ]] then Logging "${info}" "From ${location_file} To ${to_file}/${location_file##*/}" state=1 else Logging "${fatal}" "From ${location_file} To ${to_file}/${location_file##*/}" Chk_EndBackup2 Logging "${fatal}" "Backup Failure." exit 0; fi fi if [[ -f "${from_file}" ]] then cp ${from_file} ${to_file} if [[ $? -eq 0 ]] then Logging "${info}" "From ${from_file} To ${to_file}/${from_file##*/}" else Logging "${fatal}" "From ${from_file} To ${to_file}/${from_file##*/}" Chk_EndBackup2 Logging "${fatal}" "Backup Failure." exit 0; fi fi i=`expr $i - 1` done }
Chk_Space_before_backup
백업 경로에 df 명령어로 현재 디스크 여유량을 계산합니다.
디스크 여유량이 충분하다면, 물리적 복사를 시작합니다.
파일 복사시마다 성공/실패를 체크하며, 실패시 백업모드 종료 후 로그와 함께 스크립트를 종료합니다.
10. 백업을 종료합니다.
function Chk_EndBackup { if [[ "${db_name}" == "STANDALONE" ]] then $session << EOF set linesize 1024 set pagesize 10000 set timing off ALTER DATABASE END BACKUP; quit EOF else $session << EOF set linesize 1024 set pagesize 10000 set timing off ALTER DATABASE END BACKUP AT ${db_name}; quit EOF fi } function Chk_EndBackup2 { while true; do db_ebackup=`Chk_EndBackup` db_ebackup=`echo ${db_ebackup} | sed 's/\n//g'` if [[ "${db_ebackup}" == *"Database altered."* ]] || [[ "${db_ebackup}" == *"ERR-HY000(14080): cannot end backup; database is not in backup"* ]] then Logging "${info}" "ALTER DATABASE END BACKUP AT ${db_name}" Logging "${info}" "${db_ebackup}" break; else Logging "${info}" "ALTER DATABASE END BACKUP AT ${db_name}" Logging "${fatal}" "${db_ebackup}" sleep 1 fi done }
Chk_EndBackup2 if [[ "${db_ebackup}" == *"Database altered."* ]] then Logging "${info}" "Backup Success." else Logging "${fatal}" "Backup Failure." fi
백업모드 종료 실패 시 1초 후 다시 백업모드 종료를 성공할 때까지 시도합니다.
위 단계의 모든 내용은 goldilocks_backup.log 파일에 기록됩니다.
goldilocks_backup.sh 사용해보기
$ sh goldilocks_backup.sh -h Usage $ sh goldilocks_backup.sh user_name password $ sh goldilocks_backup.sh [OPTIONS] user_name password arguments: user_name user name password password options: -h Print Help Messages -m [i|h|c] Set Backup Mode (Default : h) [ ONLINE : Incremental (i), Full (h) ][ OFFLINE : Full (c) ] -p PATH Set Absolute Destination Path (Default : current path)
옵션을 부여하지 않고 아이디와 비밀번호만 입력해서 온라인 백업 수행하기
$ sh goldilocks_backup.sh SYS gliese [20180713_004120] [INFORMATION] GOLDILOCKS BACKUP START [20180713_004120] [INFORMATION] START TIME = 20180713_004120 [20180713_004120] [INFORMATION] BACKUP MODE = h [20180713_004120] [INFORMATION] BACKUP PATH = /home/sh/Appliance/Source/Script [20180713_004120] [INFORMATION] USER ID = SYS [20180713_004120] [INFORMATION] DB NAME = STANDALONE [20180713_004121] [INFORMATION] ALTER DATABASE BEGIN BACKUP AT STANDALONE [20180713_004121] [INFORMATION] Database altered. [20180713_004121] [INFORMATION] /home/sh/Appliance/Source/Script is available size 2509455360 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/conf/goldilocks.properties.conf size is 18698 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/conf/goldilocks.properties.binary does not exist [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/trc/system.trc size is 26309 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/wal/control_0.ctl size is 11264 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/wal/control_1.ctl size is 11264 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/backup/control.tmp does not exist [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/db/system_dict.dbf size is 268435456 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/db/system_undo.dbf size is 33554432 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/db/system_data.dbf size is 209715200 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/wal/redo_0_0.log size is 104857600 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/wal/redo_1_0.log size is 104857600 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/wal/redo_2_0.log size is 104857600 Bytes [20180713_004121] [INFORMATION] /home/sh/goldilocks_data/wal/redo_3_0.log size is 104857600 Bytes [20180713_004121] [INFORMATION] From /home/sh/goldilocks_data/wal/redo_3_0.log To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/wal/redo_3_0.log [20180713_004121] [INFORMATION] From /home/sh/goldilocks_data/wal/redo_2_0.log To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/wal/redo_2_0.log [20180713_004121] [INFORMATION] From /home/sh/goldilocks_data/wal/redo_1_0.log To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/wal/redo_1_0.log [20180713_004121] [INFORMATION] From /home/sh/goldilocks_data/wal/redo_0_0.log To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/wal/redo_0_0.log [20180713_004121] [INFORMATION] From /home/sh/goldilocks_data/db/system_data.dbf To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/db/system_data.dbf [20180713_004121] [INFORMATION] From /home/sh/goldilocks_data/db/system_undo.dbf To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/db/system_undo.dbf [20180713_004122] [INFORMATION] From /home/sh/goldilocks_data/db/system_dict.dbf To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/db/system_dict.dbf [20180713_004122] [INFORMATION] From /home/sh/goldilocks_data/wal/control_1.ctl To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/wal/control_1.ctl [20180713_004122] [INFORMATION] From /home/sh/goldilocks_data/wal/control_0.ctl To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/wal/control_0.ctl [20180713_004122] [INFORMATION] From /home/sh/goldilocks_data/trc/system.trc To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/trc/system.trc [20180713_004122] [INFORMATION] From /home/sh/goldilocks_data/conf/goldilocks.properties.conf To /home/sh/Appliance/Source/Script/20180713_004120/home/sh/goldilocks_data/conf/goldilocks.properties.conf [20180713_004122] [INFORMATION] ALTER DATABASE END BACKUP AT STANDALONE [20180713_004122] [INFORMATION] Database altered. [20180713_004122] [INFORMATION] Backup Success.
옵션을 부여하여 온라인 백업 수행하기
$ sh goldilocks_backup.sh -m h -p /home/sh/Appliance/Source/Script SYS gliese [20180713_004221] [INFORMATION] GOLDILOCKS BACKUP START [20180713_004221] [INFORMATION] START TIME = 20180713_004221 [20180713_004221] [INFORMATION] BACKUP MODE = h [20180713_004221] [INFORMATION] BACKUP PATH = /home/sh/Appliance/Source/Script [20180713_004221] [INFORMATION] USER ID = SYS [20180713_004221] [INFORMATION] DB NAME = STANDALONE [20180713_004222] [INFORMATION] ALTER DATABASE BEGIN BACKUP AT STANDALONE [20180713_004222] [INFORMATION] Database altered. [20180713_004222] [INFORMATION] /home/sh/Appliance/Source/Script is available size 2509455360 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/conf/goldilocks.properties.conf size is 18698 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/conf/goldilocks.properties.binary does not exist [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/trc/system.trc size is 29734 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/wal/control_0.ctl size is 11264 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/wal/control_1.ctl size is 11264 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/backup/control.tmp does not exist [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/db/system_dict.dbf size is 268435456 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/db/system_undo.dbf size is 33554432 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/db/system_data.dbf size is 209715200 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/wal/redo_0_0.log size is 104857600 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/wal/redo_1_0.log size is 104857600 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/wal/redo_2_0.log size is 104857600 Bytes [20180713_004222] [INFORMATION] /home/sh/goldilocks_data/wal/redo_3_0.log size is 104857600 Bytes [20180713_004222] [INFORMATION] From /home/sh/goldilocks_data/wal/redo_3_0.log To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/wal/redo_3_0.log [20180713_004222] [INFORMATION] From /home/sh/goldilocks_data/wal/redo_2_0.log To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/wal/redo_2_0.log [20180713_004222] [INFORMATION] From /home/sh/goldilocks_data/wal/redo_1_0.log To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/wal/redo_1_0.log [20180713_004222] [INFORMATION] From /home/sh/goldilocks_data/wal/redo_0_0.log To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/wal/redo_0_0.log [20180713_004222] [INFORMATION] From /home/sh/goldilocks_data/db/system_data.dbf To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/db/system_data.dbf [20180713_004222] [INFORMATION] From /home/sh/goldilocks_data/db/system_undo.dbf To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/db/system_undo.dbf [20180713_004222] [INFORMATION] From /home/sh/goldilocks_data/db/system_dict.dbf To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/db/system_dict.dbf [20180713_004222] [INFORMATION] From /home/sh/goldilocks_data/wal/control_1.ctl To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/wal/control_1.ctl [20180713_004222] [INFORMATION] From /home/sh/goldilocks_data/wal/control_0.ctl To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/wal/control_0.ctl [20180713_004223] [INFORMATION] From /home/sh/goldilocks_data/trc/system.trc To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/trc/system.trc [20180713_004223] [INFORMATION] From /home/sh/goldilocks_data/conf/goldilocks.properties.conf To /home/sh/Appliance/Source/Script/20180713_004221/home/sh/goldilocks_data/conf/goldilocks.properties.conf [20180713_004223] [INFORMATION] ALTER DATABASE END BACKUP AT STANDALONE [20180713_004223] [INFORMATION] Database altered. [20180713_004223] [INFORMATION] Backup Success.
진행 중 실패할 경우 (2개만)
스크립트가 이미 구동중인 경우 다음과 같이 FATAL 로그가 찍힙니다.
$ sh goldilocks_backup.sh SYS gliese [20180713_000000] [FATAL] Goldilocks Backup Script is Already Started
아카이브 모드가 아닌 경우 다음과 같이 FATAL 로그가 찍힙니다.
$ sh goldilocks_backup.sh -m h -p /home/sh/Appliance/Source/Script SYS gliese [20180713_004518] [INFORMATION] GOLDILOCKS BACKUP START [20180713_004518] [INFORMATION] START TIME = 20180713_004518 [20180713_004518] [INFORMATION] BACKUP MODE = h [20180713_004518] [INFORMATION] BACKUP PATH = /home/sh/Appliance/Source/Script [20180713_004518] [INFORMATION] USER ID = SYS [20180713_004518] [INFORMATION] DB NAME = STANDALONE [20180713_004518] [INFORMATION] ALTER DATABASE BEGIN BACKUP AT STANDALONE [20180713_004518] [FATAL] ERR-HY000(16247): cannot BACKUP; noarchivelog mode
'Linux > 실습하기' 카테고리의 다른 글
[LINUX] 쉘 스크립트 파일 한 줄씩 읽을 때 ssh 를 사용하면 한줄만 읽는 문제 (0) | 2020.10.12 |
---|---|
[LINUX] 물리메모리를 전부 사용하지 않았는데 SWAP 영역을 사용하는 원인 (1) | 2020.09.23 |
[LINUX] 비밀번호를 출력하지 않는 스크립트 만들기 (0) | 2018.09.11 |
[LINUX] CENTOS 에 JEUS 웹서버 설치하기 (0) | 2018.06.28 |