关于bash:自用RAC配置脚本

#!/bin/bash## Linux7上装置Oracle数据库一键配置脚本# 装置介质所在目录# You must put the installation package in the /tmp/soft directory, Like this:# /tmp/soft/# ├── 11# ├── 12# ├── 19# │ ├── LINUX.X64_193000_db_home.zip# │ ├── LINUX.X64_193000_grid_home.zip# │ ├── p34773504_190000_Linux-x86-64_OJVM+GI_RU_19.18.0.0.230117.zip# │ ├── p6880880_190000_Linux-x86-64-OPatch_12.2.0.1.36.zip# │ └── patch# │ ├── 34762026# │ ├── 34786990# │ ├── PatchSearch.xml# │ └── README.html# └── compat-libstdc++-33-3.2.3-72.el7.x86_64.rpm# 定义变量# db_type | si/SI --单实例;rac/RAC --RAC(两节点)export db_type=RAC# 定义 Public IP、Virtual IP、SCAN IP 等业务网段 IP 地址信息export PubIP1=192.168.11.31export hostname1=Jeff-Test-RAC01export PubIP2=192.168.11.32export hostname2=Jeff-Test-RAC02export VIP1=192.168.11.33export VIP1NAME=Jeff-Test-VIP1export VIP2=192.168.11.34export VIP2NAME=Jeff-Test-VIP2export SCANIP=192.168.11.35export SCANNAME=Jeff-Test-SCAN# Pub_Mask 业务网络子网掩码,数字 23 或者 255.255.254.0 均反对export Pub_Mask=23export scanPort=1525export cluster_name=Jeff-Testexport ORA_SID_PREFIX=Jeff0export DB_NAME=Jeffexport DB_UNIQUE_NAME=JeffTestexport ORA_SID1=Jeff01export ORA_SID2=Jeff02# 定义心跳网络 Private IP 信息export PrivIP1=11.11.11.31export Priv1NAME=Jeff-Test-Priv1export PrivIP2=11.11.11.32export Priv2NAME=Jeff-Test-Priv2# Priv_Mask 心跳网络子网掩码,数字 23 或者 255.255.254.0 均反对export Priv_Mask=24# ntpserver 用于配置 chronyd 服务export ntpserver=11.11.11.1# oraver:装置的数据库版本:11、12、18、19、23export oraver=19# 指定root明码、oracle&grid明码、DB治理明码export rootpw="Test01"export ORAPWD="Oracle_19C" # oracle && grid 设置雷同明码export db_admin_pwd="Oracle_19C" # 预设数据库治理应用的对立明码# needcdb 指定是否Y(y)须要 CDB 容器数据库,needpdb 是否Y(y)须要创立 PDB(限度创立 1 个),PDB_SID 指定 PDB 名字export needcdb=Yexport needpdb=yexport PDB_SID=Jeff_PDB# 指定内存、FRA参数设置,如下是很小的参数了,再小会导致装置失败export sgasize=1800MBexport sga_max_size=2000MBexport pgasize=600MBexport recovery_size=18000MBexport processes=5000# 软件装置目录设置export rootdir=/u01export ORA_BASE=$rootdir/app/oracleexport ORA_HOME=$ORA_BASE/product/19.3.0/db_1export ORA_INV=$rootdir/app/oraInventoryexport GI_BASE=$rootdir/app/gridexport GI_HOME=$rootdir/app/19.3.0/gridexport logfile=/tmp/install_$(date +%F).log# ASM 磁盘组调配# mapper_dir 指定提供给ASM治理的磁盘辨认门路,或者 /dev/mapper 等export mapper_dir=/dev# sd : 提供给ASM治理的磁盘前缀export mapper_prefix=sd# asm_ocr_disks: OCR\Voting 磁盘组,多组应用空格\,\;等字符隔开,倡议命令行应用,,不容易凌乱;不写前缀export asm_ocr_disks="b c d"export asm_ocr_dir=OCR# asm_fra_disks:归档日志、闪回区 磁盘组export asm_fra_disks="e f g"export asm_fra_dir=FRA# asm_data_disks:数据文件 磁盘组;默认 redo 寄存 $asm_data_dir 和 $asm_fra_dir,须要另外配置则调整脚本export asm_data_disks="h"export asm_data_dir=DATA# 指定是否须要格式化磁盘 Y(y)格式化,其余不执行export need_format=y# 装置介质指定export softroot=/tmp/softexport softdir=$softroot/$oraverexport db_zip_file=LINUX.X64_193000_db_home.zipexport grid_zip_file=LINUX.X64_193000_grid_home.zipexport opatch_zip_file=p6880880_190000_Linux-x86-64-OPatch_12.2.0.1.36.zipexport ru=34762026############################################ 以上是主要参数定义,以下局部可不设置 ############################################# 以下局部没有参数设置split1() { echo -e "\033[1;40;33m\n\n ===================================== $(date +'%F %T') =====================================\n$1\033[0m"}result_err() { echo -e "\033[5;31m\n (*>﹏<*)(*>﹏<*)(*>﹏<*) $1 (*>﹏<*)(*>﹏<*)(*>﹏<*)\n\033[0m"}result_ok() { echo -e "\n\033[32m (*^_^*)(*^_^*)(*^_^*) $1 (*^_^*)(*^_^*)(*^_^*)\033[0m\n"}# db_zip_file 默认值 LINUX.X64_193000_db_home.zipif [ -z ${db_zip_file} ];then db_zip_file=LINUX.X64_193000_db_home.zipfi# grid_zip_file 默认值 LINUX.X64_193000_grid_home.zipif [ -z ${grid_zip_file} ];then grid_zip_file=LINUX.X64_193000_grid_home.zipfi# opatch_zip_file 默认值 p6880880_190000_Linux-x86-64.zip,每次下载最新文件if [ -z ${opatch_zip_file} ];then opatch_zip_file=p6880880_190000_Linux-x86-64.zipfi# 须要apply的RU,不 apply 则置空export ru_zip_file=$softdir/p${ru}*.zip# 辨认 RU 对应的 zip 文件export RUs=$softdir/patch/$ru# 装置时须要同时装置的 RU 绝对路径if [ -d $softroot ] && [ ! -d $softdir/patch ];then mkdir -p $softdir/patchfiecho "################ Begin : $(date +'%F %T') ################">$logfilechmod -R 777 $softrootexport db_install_file=$softdir/$db_zip_fileexport grid_install_file=$softdir/$grid_zip_fileexport opatch_install_file=$softdir/$opatch_zip_fileexport upper_db_type=$(echo $db_type | tr [:lower:] [:upper:])if [ ! -f ${db_install_file} ];then result_err "Error: DB install file not found!" >>$logfile exit 1 elif [ ${upper_db_type} == "RAC" ] && [ ! -f ${grid_install_file} ];then result_err "You select Db type as RAC, But can not found GRID install file!">>$logfile exit 1 elif [ -n ${ru} ] && [ ! -f ${ru_zip_file} ];then result_err "You Want to apply an RU, But not found zip file!">>$logfile exit 1 if [ ! -f ${opatch_install_file} ];then result_err "You choose to apply RU and must update OPatch">>$logfile exit 1 fifisplit1 "# 依照输出参数解析各文件压缩包名如下,The input installation media is analyzed as follows:DB install file: $db_install_fileGRID install file: $grid_install_fileOPatch install file: $opatch_install_fileRU zip file: $ru_zip_file">>$logfilesplit1 "# 依照输出参数解析各文件压缩包名如下,The input installation media is analyzed as follows:DB install file: $db_install_fileGRID install file: $grid_install_fileOPatch install file: $opatch_install_fileRU zip file: $ru_zip_file"sleep 5# 如下实现掩码数字计算:255.255.254.0 转换 23export tmp1=$(echo $Pub_Mask | grep -o '\.' | wc -l)if [ $tmp1 -eq 3 ]; then export Pub_Mask=$(echo $Pub_Mask | sed 's/\./ + /g;s/255/8/g;s/254/7/g;s/252/6/g;s/248/5/g;s/240/4/g;s/224/3/g;s/192/2/g;s/128/1/g' | bc)elif [ $tmp1 -gt 0 ]; then result_err "# 请输出正确的 Public 网卡子网掩码($Pub_Mask)">>$logfile exit 1elif [ $Pub_Mask -lt 32 ] && [ $Pub_Mask -gt 1 ] && [ $tmp1 -eq 0 ]; then echo -eelse result_err "# 请输出正确的 Public($Pub_Mask) 网卡掩码位数字 2-31">>$logfile exit 1fiecho "# SCAN_IP: $SCANIP/$Pub_Mask" >>$logfileexport tmp2=$(echo $Priv_Mask | grep -o '\.' | wc -l)if [ $tmp2 -eq 3 ]; then export Priv_Mask=$(echo $Priv_Mask | sed 's/\./ + /g;s/255/8/g;s/254/7/g;s/252/6/g;s/248/5/g;s/240/4/g;s/224/3/g;s/192/2/g;s/128/1/g' | bc)elif [ $tmp2 -gt 0 ]; then result_err "# 请输出正确的 Private 网卡子网掩码($Priv_Mask)">>$logfile exit 1elif [ $Priv_Mask -lt 32 ] && [ $Priv_Mask -gt 1 ] && [ $tmp2 -eq 0 ]; then echo -eelse result_err "# 请输出正确的 Private($Priv_Mask) 网卡掩码位数字 2-31">>$logfile exit 1fiecho "# PrivIP1: $PrivIP1/$Priv_Mask" >>$logfile# 获取子网函数get_ipgate() { #ip地址转换整数 ipgate_int=$(echo $1 | awk -F'.' '{print $1*(256^3) + $2*(256^2) + $3*256 + $4}') #主机位:32 - $2 #按位运算,右移,ip地址移除主机位,保留网络位 #按位运算,左移,ip地址以0补全主机位 ((ipgate = ((ipgate_int >> ((32 - $2)))) << ((32 - $2)))) #获取子网:整数转换ip地址,整数右移取低8位 echo $((ipgate >> 24 & 0xFF)).$((ipgate >> 16 & 0xFF)).$((ipgate >> 8 & 0xFF)).$((ipgate & 0xFF))}export scan_subnet=$(get_ipgate $SCANIP $Pub_Mask)export priv_subnet=$(get_ipgate $PrivIP1 $Priv_Mask)echo "# pub-subnet: $scan_subnet ; Priv-subnet: $priv_subnet">>$logfilenetcard_name() { findIP=$1 # 依照网卡名行,结尾为数字编号,进行过滤抉择 for devEnum in $(ip link show | grep ^[0-9]\\+: | awk -F ' ' {'print $2'}); do # 去掉后缀冒号 devName=${devEnum%:} # 去掉可能的子网卡接口后缀 devName=${devName%@*} if [ $(ip addr show $devName | grep -c $findIP) -gt 0 ]; then echo $devName break fi done}if [ "$(hostname)" == "$hostname1" ]; then pub_netcard=$(netcard_name $PubIP1) priv_netcard=$(netcard_name $PrivIP1) echo "# pub_netcard: $pub_netcard ; priv_netcard: $priv_netcard" >>$logfilefi# 提取 ASM 磁盘信息,转换后提供 for 循环应用(-->21 asm 配置)export asm_ocr_disks=$(echo $asm_ocr_disks | sed 's/,/ /g' | sed 's/\./ /g' | sed 's/;/ /g' | sed 's/\// /g' | sed 's/\\/ /g')export asm_fra_disks=$(echo $asm_fra_disks | sed 's/,/ /g' | sed 's/\./ /g' | sed 's/;/ /g' | sed 's/\// /g' | sed 's/\\/ /g')export asm_data_disks=$(echo $asm_data_disks | sed 's/,/ /g' | sed 's/\./ /g' | sed 's/;/ /g' | sed 's/\// /g' | sed 's/\\/ /g')# 确认长期安装文件存储目录 /tmp 存在,且可用空间大于 10GBecho "# $(hostname) 查看 /tmp 目录存在,且可用空间大于 10GB:" >>$logfileif [ ! -d /tmp ]; then echo "# /tmp Filesystem does not exist,Create it." >>$logfile mkdir /tmpfiexport tmpsizemb=$(cd /tmp && df -PmT . | grep -v Filesystem | awk '{print $5}')if [ $tmpsizemb -lt 10240 ]; then cd /tmp && df -PmT . result_err "# /tmp Filesystem has size $tmpsizemb MB, less than 10G, exit this scripts." result_err "# /tmp Filesystem has size $tmpsizemb MB, less than 10G, exit this scripts." >>$logfile exit 1fi# 0. yum 查看及装置依赖包split1 "# 0. 查看 yum 装置源是否可用,并装置依赖包($(hostname)):"if [ $(hostname) == "$hostname1" ]; then split1 "# 0. 查看 yum 装置源是否可用,并装置依赖包($(hostname)):" >>$logfile echo '#!/bin/bash' >/tmp/yumlist.sh cat >>/tmp/yumlist.sh <<yumlistexport yumlist=\$(yum list 2>/dev/null | wc -l)if [ \$yumlist -gt 2000 ]; then export yumusable=1 echo "# yum avaliable on \$(hostname)"else export yumusable=0 echo "# YUM Unavailable on \$(hostname), Try to mount /dev/cdrom make it available" if [ -h /dev/cdrom ];then echo "# /dev/cdrom exist, mount it to /mnt for use" mount /dev/cdrom /mnt/ if [ ! -d /etc/yum.repos.d/bak ]; then mkdir /etc/yum.repos.d/bak fi mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak/ echo "[Local_mnt]name=Local_mntbaseurl=file:///mntenabled=1gpgcheck=0" >/etc/yum.repos.d/Local_mnt.repo yum -y clean all yum makecache else echo "# /dev/cdrom does not exist, do nothing." fi if [ \$(yum list 2>/dev/null | wc -l) -lt 2000 ];then echo "# Yum is not available on \$(hostname), try Failed" exit 1 fifi# Install need rpmsecho "# Installing need rpms on \$(hostname) ... ..."sleep 5yum install -y bc binutils compat-libcap1 compat-libstdc++-33 elfutils-libelf elfutils-libelf-devel fontconfig-devel glibc glibc-devel ksh libaio libaio-devel libXrender libXrender-devel libX11 libXau libXi libXtst libgcc libstdc++ libstdc++-devel libxcb make policycoreutils policycoreutils-python smartmontools sysstat net-tools nfs-utils python python-configshell python-rtslib python-six targetcli xorg-x11-xauth xorg-x11-fonts-* xorg-x11-font-utils xorg-x11-fonts-Type1 xorg-x11-apps xclock ncurses-devel redhat-lsb-core readline-devel vim-enhanced bzip2 chrony iotop xterm lsof tree expect gcc-c++ zip unzip 2>/dev/nullyumlist chmod 777 /tmp/yumlist.sh sh /tmp/yumlist.sh >>$logfile if [ $? -ne 0 ]; then result_err "# $PubIP1 执行 yumlist.sh, Failed" result_err "# $PubIP1 执行 yumlist.sh, Failed" >>$logfile cat /tmp/yumlist.sh >>$logfile exit 1 else result_ok "# $PubIP1 执行 yumlist.sh, successful" result_ok "# $PubIP1 执行 yumlist.sh, successful" >>$logfile fi expect >>$logfile <<EOFset timeout 100spawn ssh -o StrictHostKeyChecking=no $PubIP2expect { "(yes/no)" {send "yes\r"; exp_continue} "password:" {send "$rootpw\r"}}expect "root@*" {send "if \[ ! -d /tmp \]; then mkdir /tmp; fi\r"}expect "root@*" {send "exit\r"}expect eofEOF # 近程 $hostname2 做雷同脚本 # 拷贝脚本到对端 echo "# 近程 $hostname2 执行雷同 yumlist 脚本" echo "# 近程 $hostname2 执行雷同 yumlist 脚本" >>$logfile if [ $(grep $PubIP2 ~/.ssh/authorized_keys 2>/dev/null | wc -l) -lt 1 ];then expect >>$logfile <<EOFset timeout 100spawn scp /tmp/yumlist.sh $PubIP2:/tmp/expect { "password:" {send "$rootpw\r"}}expect eofEOF else scp /tmp/yumlist.sh $PubIP2:/tmp/ fi if [ $? -ne 0 ]; then result_err "# scp yumlist.sh 到 $PubIP2, Failed" result_err "# scp yumlist.sh 到 $PubIP2, Failed" >>$logfile exit 1 else result_ok "# scp yumlist.sh 到 $PubIP2, successful" result_ok "# scp yumlist.sh 到 $PubIP2, successful" >>$logfile fi # 执行脚本 expect >>$logfile <<EOFset timeout 100spawn ssh $PubIP2expect { "password:" {send "$rootpw\r"}}expect "root@*" {send "sh /tmp/yumlist.sh\r"}expect "root@*" {send "exit\r"}expect eofEOF if [ $? -ne 0 ]; then result_err "# $PubIP2 执行 yumlist.sh, Failed" result_err "# $PubIP2 执行 yumlist.sh, Failed" >>$logfile exit 1 else result_ok "# $PubIP2 执行 yumlist.sh, successful" result_ok "# $PubIP2 执行 yumlist.sh, successful" >>$logfile fielse result_err "# Please run this script on $hostname1 node!" result_err "# Please run this script on $hostname1 node!" >>$logfile exit 1fi# 1. 配置hostssplit1 "# 1. 配置 $(hostname) /etc/hosts 文件:"split1 "# 1. 配置 $(hostname) /etc/hosts 文件:" >>$logfilehostnamectl set-hostname $hostname1 --staticcp /etc/hosts /etc/hosts_$(date +"%Y%m%d_%H%M%S")sed -i "/IP\|^$\|$PubIP1\|$PubIP2\|$PrivIP1\|$PrivIP2\|$VIP1\|$VIP2\|$SCANIP/d" /etc/hostsecho "# Public IP$PubIP1 $hostname1$PubIP2 $hostname2# Private IP$PrivIP1 $Priv1NAME$PrivIP2 $Priv2NAME# Virtual IP (VIP)$VIP1 $VIP1NAME$VIP2 $VIP2NAME# SCAN IP$SCANIP $SCANNAME" >>/etc/hostscat /etc/hosts >>$logfile# 拷贝脚本到对端echo "# 拷贝 /etc/hosts 文件到 $hostname2 :" echo "# 拷贝 /etc/hosts 文件到 $hostname2 :" >>$logfileexpect >>$logfile<< EOFset timeout 100spawn scp /etc/hosts $PubIP2:/etc/expect { "password:" {send "$rootpw\r"}}expect eofEOF# 执行脚本expect >>$logfile << EOFset timeout 100spawn ssh $PubIP2expect { "password:" {send "$rootpw\r"}}expect "root@*" {send "hostnamectl set-hostname $hostname2 --static\r"}expect "root@*" {send "exit\r"}expect eofEOF# 2. 配置 OS 组及用户# https://docs.oracle.com/en/database/oracle/oracle-database/19/cwsol/example-of-creating-minimal-groups-users-paths.html#GUID-103186A1-74E0-42A8-AC3D-15AF833DCB40split1 "# 2. 配置 OS 组及用户 on $(hostname) :"split1 "# 2. 配置 OS 组及用户 on $(hostname) :" >>$logfileecho '#!/bin/bash' >/tmp/usergrp.shcat >>/tmp/usergrp.sh <<usergecho "# \$(hostname) 配置 OS 组及用户:"groupadd -g 54321 oinstallgroupadd -g 54322 dbagroupadd -g 54323 opergroupadd -g 54324 backupdbagroupadd -g 54325 dgdbagroupadd -g 54326 kmdbagroupadd -g 54327 asmdbagroupadd -g 54328 asmopergroupadd -g 54329 asmadmingroupadd -g 54330 racdbau1=\$(grep oracle /etc/passwd | wc -l)u2=\$(grep oracle /etc/passwd | wc -l)if [ \$u1 -ge 1 ]; then userdel oraclefiif [ \$u2 -ge 1 ]; then userdel gridfiuseradd -g oinstall -G dba,oper,backupdba,dgdba,kmdba,asmdba,asmoper,asmadmin,racdba -u 1000 -m oracleuseradd -g oinstall -G dba,asmdba,asmoper,asmadmin,racdba -u 1001 -m gridecho "$ORAPWD" | passwd --stdin oracleecho "$ORAPWD" | passwd --stdin gridmkdir -p $GI_HOMEmkdir -p $GI_BASEmkdir -p $ORA_BASEmkdir -p $ORA_HOMEmkdir -p $ORA_INVchown -R grid:oinstall $rootdirchown -R oracle:oinstall $ORA_BASEchmod -R 775 $rootdirusergchmod +x /tmp/usergrp.sh; sh /tmp/usergrp.sh >>$logfile# 拷贝脚本到 $hostname2 并执行echo "# 拷贝脚本 /tmp/usergrp.sh 到 $hostname2 并执行:"echo "# 拷贝脚本 /tmp/usergrp.sh 到 $hostname2 并执行:" >>$logfileexpect >>$logfile << EOFset timeout 100spawn scp /tmp/usergrp.sh $PubIP2:/tmp/expect { "(yes/no)" {send "yes\r"; exp_continue} "password:" {send "$rootpw\r"}}expect eofEOF# 执行脚本expect >>$logfile << EOFset timeout 100spawn ssh $PubIP2expect { "password:" {send "$rootpw\r"}}expect "root@*" {send "sh /tmp/usergrp.sh\r"}expect "root@*" {send "exit\r"}expect eofEOF# 3. 设置环境变量配置文件split1 "# 3. 设置环境变量配置文件 .bash_profile:"split1 "# 3. 设置环境变量配置文件 .bash_profile:" >>$logfileif [ "$(hostname)" == "$hostname1" ]; then # For root on node01 sed -i '/ORACLE_HOME/d' /root/.bash_profile echo "export ORACLE_HOME=$GI_HOMEexport GRID_HOME=\$ORACLE_HOMEexport PATH=\$PATH:\$ORACLE_HOME/bin:\$ORACLE_HOME/OPatch" >>/root/.bash_profile echo -e "# root: \n$(cat /root/.bash_profile)\n" >>$logfile # For root on node02 expect >>$logfile << EOFset timeout 100spawn scp /root/.bash_profile $PubIP2:/root/expect { "password:" {send "$rootpw\r"}}expect eofEOF # # For oracle on node01 sed -i '/export\|alias\|umask\|^$/d' /home/oracle/.bash_profile cat >>/home/oracle/.bash_profile <<EOFumask 022export TMP=/tmpexport TMPDIR=\$TMPexport ORACLE_HOSTNAME=$hostname1export ORACLE_BASE=$ORA_BASEexport ORACLE_HOME=$ORA_HOMEexport ORACLE_SID=$ORA_SID1export ORACLE_INVENTORY=$ORA_INVexport INVENTORY_LOCATION=\$ORACLE_INVENTORY# export ORACLE_PDB_SID=$PDB_SIDexport NLS_LANG="AMERICAN_AMERICA.AL32UTF8"export NLS_DATE_FORMAT="yyyy-mm-dd HH24:MI:SS"export TNS_ADMIN=\$ORACLE_HOME/network/adminexport LD_LIBRARY_PATH=\$ORACLE_HOME/lib:/lib:/usr/libexport PATH=.:\$PATH:\$HOME/bin:\$ORACLE_HOME/bin:\$ORACLE_HOME/OPatchexport THREADS_FLAG=native# alias sqlplus='rlwrap sqlplus'# alias rman='rlwrap rman'alias ss='sqlplus / as sysdba'EOF echo -e "# oracle: \n$(cat /home/oracle/.bash_profile)\n" >>$logfile # For oracle on node02 expect >>$logfile << EOFset timeout 100spawn scp /home/oracle/.bash_profile oracle@$PubIP2:/home/oracle/expect { "password:" {send "$ORAPWD\r"}}expect eofEOF# 执行脚本expect >>$logfile << EOFset timeout 100spawn ssh oracle@$PubIP2expect { "password:" {send "$ORAPWD\r"}}expect "oracle@*" {send "sed -i 's/$ORA_SID1/$ORA_SID2/g' /home/oracle/.bash_profile\r"}expect "oracle@*" {send "sed -i 's/$hostname1/$hostname2/g' /home/oracle/.bash_profile\r"}expect "oracle@*" {send "exit\r"}expect eofEOF # # For grid on node01 sed -i '/export\|alias\|umask\|^$/d' /home/grid/.bash_profile cat >>/home/grid/.bash_profile <<EOFumask 022export TMP=/tmpexport TMPDIR=\$TMPexport ORACLE_HOSTNAME=$hostname1export ORACLE_SID=+ASM1export ORACLE_BASE=$GI_BASEexport GRID_BASE=\$ORACLE_BASEexport ORACLE_HOME=$GI_HOMEexport GRID_HOME=\$ORACLE_HOMEexport ORACLE_INVENTORY=$ORA_INVexport INVENTORY_LOCATION=\$ORACLE_INVENTORYexport NLS_LANG="AMERICAN_AMERICA.AL32UTF8"export NLS_DATE_FORMAT="yyyy-mm-dd HH24:MI:SS"export TNS_ADMIN=\$ORACLE_HOME/network/adminexport LD_LIBRARY_PATH=\$ORACLE_HOME/lib:/lib:/usr/libexport PATH=.:\$PATH:\$HOME/bin:\$ORACLE_HOME/bin:\$ORACLE_HOME/OPatchexport THREADS_FLAG=native# alias sqlplus='rlwrap sqlplus'# alias rman='rlwrap rman'alias ss='sqlplus / as sysasm'EOF echo -e "# grid: \n$(cat /home/grid/.bash_profile)\n" >>$logfile # For grid on node02 expect >>$logfile << EOFset timeout 100spawn scp /home/grid/.bash_profile grid@$PubIP2:/home/grid/expect { "(yes/no)" {send "yes\r"; exp_continue} "password:" {send "$ORAPWD\r"}}expect eofEOF# 执行脚本expect >>$logfile << EOFset timeout 100spawn ssh grid@$PubIP2expect { "(yes/no)" {send "yes\r"; exp_continue} "password:" {send "$ORAPWD\r"}}expect "grid@*" {send "sed -i 's/ASM1/ASM2/g' /home/grid/.bash_profile\r"}expect "grid@*" {send "sed -i 's/$hostname1/$hostname2/g' /home/grid/.bash_profile\r"}expect "grid@*" {send "exit\r"}expect eofEOFelse result_err "# Please execute this script on $hostname1,while this machine hostname is: $(hostname)" result_err "# Please execute this script on $hostname1,while this machine hostname is: $(hostname)" >>$logfile exit 1fiif [ $? -ne 0 ]; then result_err "# 设置环境变量, Failed" result_err "# 设置环境变量, Failed" >>$logfile exit 1else result_ok "# 设置环境变量, successful" result_ok "# 设置环境变量, successful" >>$logfilefi# 4. Check OS and Configuration 查看系统配置# $ISVirtual ≥ 1, is Virtual Machine# export routeip=$(route -n | egrep -iv "Gateway|routing" | awk '{print $2}' | grep -v "0\.0\.0\.0")# export routeprefix=$(echo $routeip | awk -F"." '{print $1"."$2}')split1 "# 4. Check OS and Configuration 查看系统配置:"split1 "# 4. Check OS and Configuration 查看系统配置:" >>$logfileecho '#!/bin/bash'>/tmp/osinfo.shcat >>/tmp/osinfo.sh <<osinfoexport routeprefix=\$(route -n | egrep -iv "Gateway|routing" | awk '{print \$2}' | grep -v "0\.0\.0\.0" | awk -F"." '{print \$1"."\$2}')export client_ip=\$(ip a | grep -w inet | grep -Eiv "secondary|virbr|docker|:|127.0.0.1|192.168.1\." | awk -F " +|/" '{ print \$3}' | grep \$routeprefix)export ISVirtual=\$(dmidecode -s system-product-name | grep -i virtual | wc -l)export MachineName=\$(dmidecode -s system-product-name)if [ -f /etc/yum/pluginconf.d/subscription-manager.conf ]; then sed -i 's/enabled=1/enabled=0/g' /etc/yum/pluginconf.d/subscription-manager.conf yum remove subscription-manager -yelse echo "subscription-manager.conf file not exist, Do nothing"fiif [ \$ISVirtual -eq 0 ]; then machine_type="物理机" export RAM_GB=\$(dmidecode | grep -P -A5 "Memory\s+Device" | grep GB | awk '{sum+=\$2} END {print sum}')else machine_type="虚拟机" export RAM_GB=\$(free -g | grep Mem | awk '{print \$2}')ficpus=\$(lscpu | grep ^'CPU(s):' | awk '{print \$2}' | grep -v ^\$)sockets=\$(lscpu | grep ^'Socket(s):' | awk -F":" '{print \$2}' | grep -v ^\$ | sed 's/^[ ]*//g')cores_per_sock=\$(lscpu | grep "Core(s) per socket:" | awk -F":" '{print \$2}' | grep -v ^\$ | sed 's/^[ ]*//g')cpu_name=\$(lscpu | grep "Model name:" | awk -F":" '{print \$2}' | grep -v ^\$ | sed 's/^[ ]*//g')Cores=\$((\${sockets} * \${cores_per_sock}))echo "# \$(hostname) 硬件及OS Version信息采集: 服务器IP:\$client_ip 服务器类型:\$machine_type 机器型号/平台:\$MachineName CPU name:\$cpu_name CPU(s):\$cpus Core(s):\$Cores Socket(s):\$sockets Core(s) per socket:\$cores_per_sock"osinfochmod +x /tmp/osinfo.sh; sh /tmp/osinfo.sh >>$logfileif [ $? -ne 0 ]; then result_err "# Check OS and Configuration 查看系统配置, Failed" result_err "# Check OS and Configuration 查看系统配置, Failed" >>$logfile exit 1else result_ok "# Check OS and Configuration 查看系统配置, successful" result_ok "# Check OS and Configuration 查看系统配置, successful" >>$logfilefi# 拷贝到 $hostname2 并执行脚本expect >>$logfile << EOFset timeout 100spawn scp /tmp/osinfo.sh $PubIP2:/tmp/expect { "password:" {send "$rootpw\r"}}expect eofEOF# 执行脚本expect >>$logfile << EOFset timeout 100spawn ssh $PubIP2expect { "password:" {send "$rootpw\r"}}expect "root@*" {send "sh /tmp/osinfo.sh\r"}expect "root@*" {send "exit\r"}expect eofEOFif [ $? -ne 0 ]; then result_err "# $hostname2 查看系统配置, Failed" result_err "# $hostname2 查看系统配置, Failed" >>$logfile exit 1else result_ok "# $hostname2 查看系统配置, successful" result_ok "# $hostname2 查看系统配置, successful" >>$logfilefi# 5. 解压软件,如果存在,仅节点1执行split1 "# 5. 解压软件,如果存在,仅节点1执行:"split1 "# 5. 解压软件,如果存在,仅节点1执行:" >>$logfileif [ -f $grid_install_file ] && [ "$(hostname)" == "$hostname1" ]; then echo "# unziping grid install file to $GI_HOME..." echo "# unziping grid install file to $GI_HOME..." >>$logfile su - grid -c "unzip -qo $grid_install_file -d $GI_HOME/; mv $GI_HOME/OPatch $GI_HOME/OPatch.$(date +%Y%m%d%H%M); unzip -qo $opatch_install_file -d $GI_HOME/" >>$logfile echo -e "\n# unzip grid install file End!\n$(ls $GI_HOME/)\n" >>$logfilefiif [ -f $db_install_file ] && [ "$(hostname)" == "$hostname1" ]; then echo "# unziping DB install file to $ORA_HOME..." echo "# unziping DB install file to $ORA_HOME..." >>$logfile su - oracle -c "unzip -qo $db_install_file -d $ORA_HOME/; mv $ORA_HOME/OPatch $ORA_HOME/OPatch.$(date +%Y%m%d%H%M); unzip -qo $opatch_install_file -d $ORA_HOME/" >>$logfile echo -e "\n# unzip DB install file End!\n$(ls $ORA_HOME/)\n" >>$logfilefiif [ -f ${ru_zip_file} ] && [ "$(hostname)" == "$hostname1" ];then echo "# unziping RU zip file to $softdir/patch/..." echo "# unziping RU zip file to $softdir/patch/..." >>$logfile unzip -qo ${ru_zip_file} -d $softdir/patch/; chmod -R 777 $softdir/patch/ echo -e "\n# unzip Ru zip file End!\n$(ls -l $softdir/patch/)\n" >>$logfilefichown -R grid:oinstall $rootdirchown -R oracle:oinstall $ORA_BASEchmod -R 775 $rootdir# 测试环境空间不太够用,$rootdir 和 /tmp 都在/ 下,判断目录有余时清理zip文件tmpmnt=$(df -m /tmp/ | grep -v Filesystem | awk '{print $6}' | sed -e '/^$/d')rootdirmnt=$(df -m $rootdir | grep -v Filesystem | awk '{print $6}' | sed -e '/^$/d')rootdirleft=$(df -m $rootdir | grep -v Filesystem | awk '{print $4}' | sed -e '/^$/d')if [ "$tmpmnt" == "$rootdirmnt" ] && [ $rootdirleft -le 20480 ];then echo "# $rootdirmnt 残余空间太少,且同 zip 文件雷同文件系统,删除 zip 文件" echo "# $rootdirmnt 残余空间太少,且同 zip 文件雷同文件系统,删除 zip 文件" >>$logfile rm -rf $softdir/*.zip >>$logfileelif [ $rootdirleft -le 20480 ]; then echo "# $rootdirmnt 残余空间太少, 请留神" echo "# $rootdirmnt 残余空间太少, 请留神" >>$logfilefi# 6. 配置 ssh 互信split1 "# 6. 配置 ssh 互信(oracle grid root),仅在解压文件的节点1执行:"split1 "# 6. 配置 ssh 互信(oracle grid root),仅在解压文件的节点1执行:" >>$logfileif [ -f $GI_HOME/oui/prov/resources/scripts/sshUserSetup.sh ]; then for i in oracle grid root; do if [ "$i" == "root" ]; then export pass=$rootpw else export pass=$ORAPWD fi expect >>$logfile << EOFspawn $GI_HOME/oui/prov/resources/scripts/sshUserSetup.sh -user $i -hosts "$hostname1 $hostname2" -advanced -noPromptPassphraseexpect { "(yes/no)" {send "yes\r"; exp_continue} "*assword:" {send "$pass\r";exp_continue}}expect eofEOF expect >>$logfile << EOFspawn $GI_HOME/oui/prov/resources/scripts/sshUserSetup.sh -user $i -hosts "$Priv1NAME $Priv2NAME" -advanced -noPromptPassphraseexpect { "(yes/no)" {send "yes\r"; exp_continue} "*assword:" {send "$pass\r";exp_continue}}expect eofEOF for g in $hostname1 $hostname2 $Priv1NAME $Priv2NAME; do echo "# Testing $g for $i" >>$logfile if [ "$i" == "root" ]; then ssh -l $i -o StrictHostKeyChecking=no $g date >>$logfile else su - $i -c "ssh -l $i -o StrictHostKeyChecking=no $g date" >>$logfile fi if [ $? -ne 0 ]; then result_err "# $i Test $g sshUserSetup Maybe Failed" result_err "# $i Test $g sshUserSetup Maybe Failed" >>$logfile exit 1 else result_ok "# $i 配置 $g ssh 互信, successful" result_ok "# $i 配置 $g ssh 互信, successful" >>$logfile fi done donefi# 7. 查看 RAM\Swap\shm# swap 不须要设置过大,最大32GB,Oracle倡议是16GB(内存>=16GB);eq 内存大小(小于16GB)# shm 默认是内存的1/2,配置Oracle会不够用,调整为等同可用内存大小(自己未取总内存)split1 "# 7. 查看 RAM\Swap\shm"split1 "# 7. 查看 RAM\Swap\shm" >>$logfileecho '#!/bin/bash'>/tmp/shm.shcat >>/tmp/shm.sh<<shmecho "# 设置 /dev/shm:\$(hostname)"shmsizegb=\$(echo "scale=0;\$(df -PmT /dev/shm | grep shm | awk '{print \$3}')/1024" | bc)swapgb=\$(echo "scale=0;\$(grep SwapTotal /proc/meminfo | awk '{print \$2}')/1024/1024" | bc)memgb=\$(echo "scale=0;\$(grep MemTotal /proc/meminfo | awk '{print \$2}')/1024/1024" | bc)if [ \$shmsizegb -lt \$memgb ]; then echo "resize /dev/shm to \${memgb}G" sed -i '/\/dev\/shm/d' /etc/fstab echo "tmpfs /dev/shm tmpfs defaults,size=\${memgb}G,noatime,nodiratime 0 0" >>/etc/fstab mount -o remount /dev/shmelse echo "/dev/shm equal to MemTotal, Now \$(df -h | grep /dev/shm | awk '{print $2}')"fishmchmod +x /tmp/shm.sh;sh /tmp/shm.sh >>$logfileif [ $? -ne 0 ]; then result_err "# 查看 RAM\Swap\shm, Failed" result_err "# 查看 RAM\Swap\shm, Failed" >>$logfile exit 1else result_ok "# 查看 RAM\Swap\shm, successful" result_ok "# 查看 RAM\Swap\shm, successful" >>$logfilefiscp /tmp/shm.sh $hostname2:/tmp/ >>$logfileecho "sh /tmp/shm.sh;exit" | ssh $hostname2 >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 查看 RAM\Swap\shm, Failed" result_err "# $hostname2 查看 RAM\Swap\shm, Failed" >>$logfile exit 1else result_ok "# $hostname2 查看 RAM\Swap\shm, successful" result_ok "# $hostname2 查看 RAM\Swap\shm, successful" >>$logfilefi# 8. 禁用防火墙firewalldsplit1 "# 8. $(hostname) 禁用防火墙 firewalld:" split1 "# 8. $(hostname) 禁用防火墙 firewalld:" >>$logfilesystemctl stop firewalldsystemctl disable firewalldecho "# $hostname2 禁用防火墙 firewalld" >>$logfileecho "systemctl stop firewalld;systemctl disable firewalld;exit" | ssh $hostname2 >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 禁用防火墙 firewalld, Failed" result_err "# $hostname2 禁用防火墙 firewalld, Failed" >>$logfile exit 1else result_ok "# $hostname2 禁用防火墙 firewalld, successful" result_ok "# $hostname2 禁用防火墙 firewalld, successful" >>$logfilefi# 9. 禁用 SElinuxsplit1 "# 9. 禁用 SElinux:"split1 "# 9. 禁用 SElinux:" >>$logfileecho '#!/bin/bash' >/tmp/sel.shcat >>/tmp/sel.sh <<selecho "# 9 禁用 SElinux: \$(hostname)"if [ \$(getenforce) != "Disabled" ]; then export SELINUX=\$(grep ^SELINUX= /etc/selinux/config) if [ \$SELINUX != "SELINUX=disabled" ]; then cp /etc/selinux/config /etc/selinux/config_\$(date +"%Y%m%d_%H%M%S") && sed -i 's/SELINUX\=enforcing/SELINUX\=disabled/g' /etc/selinux/config echo "Changed SElinux configuration, reboot later..." else echo "The SELINUX configuration file has been modified before." fi setenforce 0else echo "SELINUX is already disabled, Do nothing."fiselchmod 777 /tmp/sel.sh;sh /tmp/sel.sh >>$logfileif [ $? -ne 0 ]; then result_err "# 禁用 SElinux, Failed" result_err "# 禁用 SElinux, Failed" >>$logfile exit 1else result_ok "# 禁用 SElinux, successful" result_ok "# 禁用 SElinux, successful" >>$logfilefiscp /tmp/sel.sh $hostname2:/tmp/ >>$logfileecho "sh /tmp/sel.sh;exit" | ssh $hostname2 >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 禁用 SElinux, Failed" result_err "# $hostname2 禁用 SElinux, Failed" >>$logfile exit 1else result_ok "# $hostname2 禁用 SElinux, successful" result_ok "# $hostname2 禁用 SElinux, successful" >>$logfilefi# 10. 禁用虚构网卡split1 "# 10. 禁用虚构网卡 libvirtd on $hostname1:"split1 "# 10. 禁用虚构网卡 libvirtd on $hostname1:" >>$logfilesystemctl stop libvirtdsystemctl disable libvirtdyum remove libvirt-libsecho "# 10 禁用虚构网卡,for $hostname2"echo "# 10 禁用虚构网卡,for $hostname2" >>$logfileecho "systemctl stop libvirtd;systemctl disable libvirtd;yum remove libvirt-libs;exit"|ssh $hostname2 >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 禁用虚构网卡, Failed" result_err "# $hostname2 禁用虚构网卡, Failed" >>$logfileelse result_ok "# $hostname2 禁用虚构网卡, successful" result_ok "# $hostname2 禁用虚构网卡, successful" >>$logfilefi# 11. 禁用 zeroconf 路由# Zero configuration networking(zeroconf)零配置网络服务标准,是一种用于主动生成可用IP地址的网络技术,不须要额定的手动配置和专属的配置服务器。Avahi 是Zeroconf标准的开源实现split1 "# 11. 禁用 zeroconf 路由:"split1 "# 11. 禁用 zeroconf 路由:" >>$logfile# 配置 NOZEROCONFsed -i '/NOZEROCONF/d' /etc/sysconfig/networkecho "NOZEROCONF=yes" >>/etc/sysconfig/network# 禁用 Avahisystemctl stop avahi-daemon.servicesystemctl stop avahi-daemon.socketsystemctl disable avahi-daemon.servicesystemctl disable avahi-daemon.socketecho "# 禁用 zeroconf 路由 for $hostname2:"echo "# 禁用 zeroconf 路由 for $hostname2:" >>$logfilescp /etc/sysconfig/network $hostname2:/etc/sysconfig/ >>$logfileecho "systemctl stop avahi-daemon.service;systemctl stop avahi-daemon.socket;systemctl disable avahi-daemon.service;systemctl disable avahi-daemon.socket;exit"|ssh $hostname2 >>$logfile# 12. 禁用通明大页 THP 和 NUMAsplit1 "# 12. 禁用通明大页 THP 和 NUMA:"split1 "# 12. 禁用通明大页 THP 和 NUMA:" >>$logfileecho '#!/bin/bash'>/tmp/thp.shcat >>/tmp/thp.sh<<thpecho "# 12 \$(hostname) 禁用通明大页 THP 和 NUMA:"export AnonHP=\$(grep AnonHugePages /proc/meminfo | awk '{print \$2}')export TPHstatus=\$(cat /sys/kernel/mm/transparent_hugepage/enabled | awk -F"[][]" '{print \$2}')if [ \$AnonHP -gt 0 ] || [ \$TPHstatus != "never" ]; then echo "Checked TPH is not completely disabled!" cp /etc/default/grub /etc/default/grub_\$(date +"%Y%m%d_%H%M%S") && sed -i 's/quiet"/quiet numa=off transparent_hugepage=never"/' /etc/default/grub if [ -d /sys/firmware/efi ]; then # On UEFI: echo "OS running use UEFI, Turn off TPH By grub /boot/efi/EFI/redhat/grub.cfg" cp /boot/efi/EFI/redhat/grub.cfg /boot/efi/EFI/redhat/grub.cfg_\$(date +"%Y%m%d_%H%M%S") && grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg else # On BIOS: echo "OS running use BIOS, Turn off TPH By grub /boot/grub2/grub.cfg" cp /boot/grub2/grub.cfg /boot/grub2/grub.cfg_\$(date +"%Y%m%d_%H%M%S") && grub2-mkconfig -o /boot/grub2/grub.cfg fielse echo "TPH already disabled."fised -i '/transparent_hugepage/d' /etc/rc.localsed -i "/^fi\b/Id" /etc/rc.localecho "if test -f /sys/kernel/mm/transparent_hugepage/enabled; then echo never > /sys/kernel/mm/transparent_hugepage/enabledfiif test -f /sys/kernel/mm/transparent_hugepage/defrag; then echo never > /sys/kernel/mm/transparent_hugepage/defragfi" >>/etc/rc.localthpchmod +x /tmp/thp.sh;sh /tmp/thp.sh >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname1 禁用通明大页 THP 和 NUMA, Failed" result_err "# $hostname1 禁用通明大页 THP 和 NUMA, Failed" >>$logfile exit 1else result_ok "# $hostname1 禁用通明大页 THP 和 NUMA, successful" result_ok "# $hostname1 禁用通明大页 THP 和 NUMA, successful" >>$logfilefiscp /tmp/thp.sh $hostname2:/tmp/echo "sh /tmp/thp.sh;exit" | ssh $hostname2 >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 禁用通明大页 THP 和 NUMA, Failed" result_err "# $hostname2 禁用通明大页 THP 和 NUMA, Failed" >>$logfile exit 1else result_ok "# $hostname2 禁用通明大页 THP 和 NUMA, successful" result_ok "# $hostname2 禁用通明大页 THP 和 NUMA, successful" >>$logfilefi# 13. 配置时钟同步机制 chronydsplit1 "# 13. 配置 chronyd 时钟同步机制 chronyd:"split1 "# 13. 配置 chronyd 时钟同步机制 chronyd:" >>$logfilesystemctl stop ntpdsystemctl disable ntpdsed -i "/$ntpserver\|logchange\|syslog/Id"sed -i "/server 0/i server $ntpserver iburst" /etc/chrony.confsed -i "/pool.ntp.org/d" /etc/chrony.confsed -i "/makestep/d" /etc/chrony.confecho "# Send message to syslog when clock adjustment is larger than 0.1 seconds.logchange 0.1" >>/etc/chrony.confsystemctl restart chronydsystemctl enable chronydscp /etc/chrony.conf $hostname2:/etc/ >>$logfileecho "systemctl stop ntpd;systemctl disable ntpd;systemctl restart chronyd;systemctl enable chronyd;exit"|ssh $hostname2 >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 配置 chronyd 时钟同步机制, Failed" result_err "# $hostname2 配置 chronyd 时钟同步机制, Failed" >>$logfile exit 1else result_ok "# $hostname2 配置 chronyd 时钟同步机制, successful" result_ok "# $hostname2 配置 chronyd 时钟同步机制, successful" >>$logfilefi# 14. 批改登录验证split1 "# 14. 批改 pam 登录验证:"split1 "# 14. 批改 pam 登录验证:" >>$logfilesed -i '/pam_limits.so/d' /etc/pam.d/loginecho "session required pam_limits.sosession required /lib64/security/pam_limits.so" >>/etc/pam.d/loginecho "# 14 批改 pam 登录验证:for $hostname2" >>$logfilescp /etc/pam.d/login $hostname2:/etc/pam.d/ >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 批改 pam 登录验证, Failed" result_err "# $hostname2 批改 pam 登录验证, Failed" >>$logfile exit 1else result_ok "# $hostname2 批改 pam 登录验证, successful" result_ok "# $hostname2 批改 pam 登录验证, successful" >>$logfilefi# 15. 批改 limit 资源限度split1 "# 15. 批改 /etc/security/limits.conf limit 资源限度:"split1 "# 15. 批改 /etc/security/limits.conf limit 资源限度:" >>$logfilesed -i "/oracle\|grid\|oinstall/d" /etc/security/limits.confecho "# Add oinstall group limits@oinstall soft nofile 16384@oinstall hard nofile 65536@oinstall soft nproc 16384@oinstall hard nproc 65536@oinstall soft stack 16384@oinstall hard stack 32768@oinstall soft memlock unlimited@oinstall hard memlock unlimited" >>/etc/security/limits.confecho "# 批改 /etc/security/limits.conf limit 资源限度: for $hostname2"echo "# 批改 /etc/security/limits.conf limit 资源限度: for $hostname2" >>$logfilescp /etc/security/limits.conf $hostname2:/etc/security/ >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 批改 /etc/security/limits.conf limit 资源限度, Failed" result_err "# $hostname2 批改 /etc/security/limits.conf limit 资源限度, Failed" >>$logfile exit 1else result_ok "# $hostname2 批改 /etc/security/limits.conf limit 资源限度, successful" result_ok "# $hostname2 批改 /etc/security/limits.conf limit 资源限度, successful" >>$logfilefi# 16. 批改 kernel 配置split1 "# 16. 批改 /etc/sysctl.conf kernel 配置:"split1 "# 16. 批改 /etc/sysctl.conf kernel 配置:" >>$logfilesed -i '/[^fs.|^vm.|^kernel.|^net.|^$]/Id' /etc/sysctl.confmemTotal=$(grep MemTotal /proc/meminfo | awk '{print $2}')MEM=$(expr $(grep MemTotal /proc/meminfo | awk '{print $2}') \* 1024)SHMALL=$(($MEM * 9 / 10 / $(getconf PAGE_SIZE)))SHMMAX=$(($MEM * 9 / 10)) # 这里配置为 90% RAM大小# shmmax(bytes) = shmmni(page size, default 4k) * shmall (page的个数)if [ $SHMALL -lt 2097152 ]; then ## 2097152*4k/1024/1024=8G SHMALL=2097152fiSHMMAX=$((memTotal * 1024 - 1))if [ "$SHMMAX" -lt 4294967295 ]; then ## 4294967295k/1024/1024=4095MB SHMMAX=4294967295fiecho "fs.file-max = 6815744fs.aio-max-nr = 1048576kernel.sem = 250 32000 100 128kernel.shmmni = 4096kernel.shmall = $SHMALLkernel.shmmax = $SHMMAXkernel.panic_on_oops = 1net.core.rmem_default = 262144net.core.rmem_max = 41943044net.core.wmem_default = 262144net.core.wmem_max = 4194304net.ipv4.ip_local_port_range = 10000 65500net.ipv4.conf.all.rp_filter = 2net.ipv4.conf.default.rp_filter = 2net.ipv6.conf.all.disable_ipv6 = 1net.ipv6.conf.default.disable_ipv6 = 1net.ipv4.tcp_max_tw_buckets = 10000net.ipv4.tcp_tw_reuse = 1net.ipv4.tcp_keepalive_time = 30net.ipv4.tcp_keepalive_intvl = 10net.ipv4.tcp_retries2 = 12net.ipv4.ip_local_reserved_ports = 15400-15407,20050-20057net.ipv4.tcp_rmem = 8192 250000 16777216net.ipv4.tcp_wmem = 8192 250000 16777216# vm.dirty_background_ratio = 5# vm.dirty_ratio = 40# vm.dirty_expire_centisecs = 500# vm.dirty_writeback_centisecs = 100# vm.min_free_kbytes= 1048576vm.swappiness = 1" >>/etc/sysctl.confsed -i '/^$/Id' /etc/sysctl.confsysctl -psysctl --system >>$logfilescp /etc/sysctl.conf $hostname2:/etc/ >>$logfileecho "sysctl -p;sysctl --system;exit"|ssh $hostname2 >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 批改 /etc/sysctl.conf kernel 配置, Failed" result_err "# $hostname2 批改 /etc/sysctl.conf kernel 配置, Failed" >>$logfile exit 1else result_ok "# $hostname2 批改 /etc/sysctl.conf kernel 配置, successful" result_ok "# $hostname2 批改 /etc/sysctl.conf kernel 配置, successful" >>$logfilefi# 17. 批改启动 runlevelsplit1 "# 17. 批改启动 runlevel=3:"split1 "# 17. 批改启动 runlevel=3:" >>$logfilesystemctl set-default multi-user.target# systemctl get-default #查看默认启动形式是什么,如果显示multi-user.target, 阐明是默认命令行启动# systemctl set-default graphical.target #设置开机默认图形桌面启动# systemctl set-default multi-user.target #设置开机默认命令行启动echo "systemctl set-default multi-user.target;exit"|ssh $hostname2 >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 批改启动 runlevel=3, Failed" result_err "# $hostname2 批改启动 runlevel=3, Failed" >>$logfile exit 1else result_ok "# $hostname2 批改启动 runlevel=3, successful" result_ok "# $hostname2 批改启动 runlevel=3, successful" >>$logfilefi# 18. 设置ssh,避免登录过慢,启用X11 Forwing 转发(默认拜访接收端6000端口split1 "# 18. 设置 /etc/ssh/sshd_config,避免登录过慢,启用X11 Forwing 转发(默认拜访接收端6000端口)"split1 "# 18. 设置 /etc/ssh/sshd_config,避免登录过慢,启用X11 Forwing 转发(默认拜访接收端6000端口)" >>$logfilecp /etc/ssh/sshd_config /etc/ssh/sshd_config_$(date +"%Y%m%d_%H%M%S") && sed -i '/UseDNS no\|^AllowTcpForwarding yes\|X11UseLocalhost no/d' /etc/ssh/sshd_configsed -i '/#UseDNS yes/a\UseDNS no' /etc/ssh/sshd_configsed -i '/#AllowTcpForwarding yes/a\AllowTcpForwarding yes' /etc/ssh/sshd_configsed -i '/#X11UseLocalhost yes/a\X11UseLocalhost no' /etc/ssh/sshd_configegrep "UseDNS|Forwarding|X11" /etc/ssh/sshd_config >>$logfilesystemctl restart sshdscp /etc/ssh/sshd_config $hostname2:/etc/ssh/ >>$logfileecho "systemctl restart sshd;exit"|ssh $hostname2 >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 设置ssh,避免登录过慢,启用X11 Forwing 转发, Failed" result_err "# $hostname2 设置ssh,避免登录过慢,启用X11 Forwing 转发, Failed" >>$logfile exit 1else result_ok "# $hostname2 设置ssh,避免登录过慢,启用X11 Forwing 转发, successful" result_ok "# $hostname2 设置ssh,避免登录过慢,启用X11 Forwing 转发, successful" >>$logfilefi# 19. 设置sudoers,授予oinstall组sudo ALL 权限split1 "# 19. 设置 /etc/sudoers,授予oinstall组sudo ALL 权限:"split1 "# 19. 设置 /etc/sudoers,授予oinstall组sudo ALL 权限:" >>$logfilecp /etc/sudoers /etc/sudoers_$(date +"%Y%m%d_%H%M%S") && sed -i '/oinstall/d' /etc/sudoers && sed -i '/^%wheel/a\%oinstall ALL=(ALL) ALL' /etc/sudoers && grep oinstall /etc/sudoersgrep oinstall /etc/sudoers >>$logfilescp /etc/sudoers $hostname2:/etc/ >>$logfileif [ $? -ne 0 ]; then result_err "# $hostname2 设置sudoers,授予oinstall组sudo ALL 权限, Failed" result_err "# $hostname2 设置sudoers,授予oinstall组sudo ALL 权限, Failed" >>$logfile exit 1else result_ok "# $hostname2 设置sudoers,授予oinstall组sudo ALL 权限, successful" result_ok "# $hostname2 设置sudoers,授予oinstall组sudo ALL 权限, successful" >>$logfilefi# 20. cvu 装置split1 "# 20. cvu 1节点装置,并传送2节点装置:"split1 "# 20. cvu 1节点装置,并传送2节点装置:" >>$logfileif [ -f $GI_HOME/cv/rpm/cvuqdisk*.rpm ]; then rpm -ivh $GI_HOME/cv/rpm/cvuqdisk*.rpm >>$logfile echo "# 2节点装置" >>$logfile scp $GI_HOME/cv/rpm/cvuqdisk*.rpm $hostname2:/tmp/ >>$logfile ssh $hostname2 rpm -ivh /tmp/cvuqdisk*.rpm >>$logfileelse result_err "# not found package cvuqdisk*.rpm" result_err "# not found package cvuqdisk*.rpm" >>$logfile exit 1fiif [ $? -ne 0 ]; then result_err "# cvu 1节点装置,并传送2节点装置, Failed" result_err "# cvu 1节点装置,并传送2节点装置, Failed" >>$logfile exit 1else result_ok "# cvu 1节点装置,并传送2节点装置, successful" result_ok "# cvu 1节点装置,并传送2节点装置, successful" >>$logfilefi# 21. asm 配置# ASM 磁盘组调配split1 "# 21. UDEV 配置磁盘,$hostname1:"split1 "# 21. UDEV 配置磁盘,$hostname1:" >>$logfile>/etc/udev/rules.d/99-oracle-asmdevices.rulesfor i in $asm_ocr_disks; do echo "KERNEL==\"${mapper_prefix}?\",SUBSYSTEM==\"block\", PROGRAM==\"/usr/lib/udev/scsi_id --whitelisted --replace-whitespace --device=$mapper_dir/\$name\",RESULT==\"$(/usr/lib/udev/scsi_id --whitelisted --replace-whitespace --device=$mapper_dir/${mapper_prefix}$i)\", SYMLINK+=\"asm_ocr_disk$i\",OWNER=\"grid\",ACTION==\"add|change\", GROUP=\"asmadmin\",MODE=\"0660\"" >>/etc/udev/rules.d/99-oracle-asmdevices.rules ocr_tmp=$(echo "$ocr_tmp""/dev/asm_ocr_disk$i,")doneexport ocr_fgs=$(echo $ocr_tmp | sed 's/,\//,,\//g')export ocr_diskgs=$(echo $ocr_tmp | sed 's/,$//')for i in $asm_fra_disks; do echo "KERNEL==\"${mapper_prefix}?\",SUBSYSTEM==\"block\", PROGRAM==\"/usr/lib/udev/scsi_id --whitelisted --replace-whitespace --device=$mapper_dir/\$name\",RESULT==\"$(/usr/lib/udev/scsi_id --whitelisted --replace-whitespace --device=$mapper_dir/${mapper_prefix}$i)\", SYMLINK+=\"asm_fra_disk$i\",OWNER=\"grid\",ACTION==\"add|change\", GROUP=\"asmadmin\",MODE=\"0660\"" >>/etc/udev/rules.d/99-oracle-asmdevices.rules fra_tmp=$(echo "$fra_tmp""/dev/asm_fra_disk$i,")doneexport fra_fgs=$(echo $fra_tmp | sed 's/,\//,,\//g')export fra_diskgs=$(echo $fra_tmp | sed 's/,$//')for i in $asm_data_disks; do echo "KERNEL==\"${mapper_prefix}?\",SUBSYSTEM==\"block\", PROGRAM==\"/usr/lib/udev/scsi_id --whitelisted --replace-whitespace --device=$mapper_dir/\$name\",RESULT==\"$(/usr/lib/udev/scsi_id --whitelisted --replace-whitespace --device=$mapper_dir/${mapper_prefix}$i)\", SYMLINK+=\"asm_data_disk$i\",OWNER=\"grid\",ACTION==\"add|change\", GROUP=\"asmadmin\",MODE=\"0660\"" >>/etc/udev/rules.d/99-oracle-asmdevices.rules data_tmp=$(echo "$data_tmp""/dev/asm_data_disk$i,")doneexport data_fgs=$(echo $data_tmp | sed 's/,\//,,\//g')export data_diskgs=$(echo $data_tmp | sed 's/,$//')systemctl restart systemd-udev-trigger.service >>$logfileudevadm control --reload-rules >>$logfileudevadm trigger --type=devices >>$logfileudevadm trigger --type=devices --action=change >>$logfilesleep 10ls -l /dev/ | grep asm >>$logfileif [ $(ssh $hostname1 ls /dev/asm* | wc -l) -lt 5 ]; then result_err "# $hostname1 UDEV 配置磁盘, Failed" result_err "# $hostname1 UDEV 配置磁盘, Failed" >>$logfile echo "$(ssh $hostname1 ls /dev/asm*)" echo "$(ssh $hostname1 ls /dev/asm*)" >>$logfile exit 1else result_ok "# $hostname1 UDEV 配置磁盘, successful" result_ok "# $hostname1 UDEV 配置磁盘, successful" >>$logfile echo "$(ssh $hostname1 ls /dev/asm*)" echo "$(ssh $hostname1 ls /dev/asm*)" >>$logfilefiecho "# $hostname2 UDEV 配置磁盘"echo "# $hostname2 UDEV 配置磁盘" >>$logfilescp /etc/udev/rules.d/99-oracle-asmdevices.rules $hostname2:/etc/udev/rules.d/ >>$logfileecho "systemctl restart systemd-udev-trigger.service;udevadm control --reload-rules;udevadm trigger --type=devices;udevadm trigger --type=devices --action=change;sleep 10;exit"|ssh $hostname2 >>$logfileif [ $(ssh $hostname2 ls /dev/asm* | wc -l) -lt 5 ]; then result_err "# $hostname2 UDEV 配置磁盘, Failed" echo "$(ssh $hostname2 ls /dev/asm*)" result_err "# $hostname2 UDEV 配置磁盘, Failed" >>$logfile echo "$(ssh $hostname2 ls /dev/asm*)" >>$logfile exit 1else result_ok "# $hostname2 UDEV 配置磁盘, successful" echo "$(ssh $hostname2 ls /dev/asm*)" result_ok "# $hostname2 UDEV 配置磁盘, successful" >>$logfile echo "$(ssh $hostname2 ls /dev/asm*)" >>$logfilefi# 格式化磁盘if [ $need_format == "y" ] || [ $need_format == "Y" ];then for i in $(ls -l /dev | grep grid | awk '{print $NF}'); do cnt=$(lsblk -b | grep -w $i | awk '{print $4/1024/1024}') echo -e "\n# 开始格式化 /dev/$i, 大小:${cnt}MB ..." echo "dd if=/dev/zero of=/dev/$i bs=1M count=$cnt" dd if=/dev/zero of=/dev/$i bs=1M count=$cnt echo "# 格式化 /dev/$i 实现" done if [ -z $i ];then result_err "# You need to format the disk, but did not execute it. Please check it." result_err "# You need to format the disk, but did not execute it. Please check it." >>$logfile exit 1 fifi# 22. 预查看split1 "# 22. grid 装置预查看(仅节点1运行):"split1 "# 22. grid 装置预查看(仅节点1运行):" >>$logfileif [ "$(hostname)" == "$hostname1" ]; then echo '#!/usr/bin/expect -f' >/tmp/precheck.sh echo "spawn $GI_HOME/runcluvfy.sh stage -pre crsinst -n $hostname1,$hostname2 -fixup -verbose -method rootexpect { \"*assword:\" {send \"$rootpw\r\";exp_continue} \"*again:\" {send \"$rootpw\r\"}}expect eof" >>/tmp/precheck.sh chmod 777 /tmp/precheck.sh su - grid -c "expect /tmp/precheck.sh" >>$logfile if [ $? -ne 0 ]; then result_err "# grid 装置预查看(仅节点1运行), Failed" result_err "# grid 装置预查看(仅节点1运行), Failed" >>$logfile exit 1 else result_ok "# grid 装置预查看(仅节点1运行), successful" result_ok "# grid 装置预查看(仅节点1运行), successful" >>$logfile fifi# 23. grid 软件装置split1 "# 23. grid 软件装置(仅节点1运行):"split1 "# 23. grid 软件装置(仅节点1运行):" >>$logfile# $ sed -e 's/[\t ]\+$//' gridsetup.rsp | egrep -v "^$|^#|=$"# oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_v19.0.0# INVENTORY_LOCATION=/u01/app/oraInventory# oracle.install.option=CRS_CONFIG# ORACLE_BASE=/u01/app/grid# oracle.install.asm.OSDBA=asmdba# oracle.install.asm.OSOPER=asmoper# oracle.install.asm.OSASM=asmadmin# oracle.install.crs.config.scanType=LOCAL_SCAN# oracle.install.crs.config.gpnp.scanName=Jeff-Test-SCAN# oracle.install.crs.config.gpnp.scanPort=1525# oracle.install.crs.config.ClusterConfiguration=STANDALONE# oracle.install.crs.config.configureAsExtendedCluster=false# oracle.install.crs.config.clusterName=Jeff-Test# oracle.install.crs.config.gpnp.configureGNS=false# oracle.install.crs.config.autoConfigureClusterNodeVIP=false# oracle.install.crs.config.clusterNodes=Ora-Jeff-Test-Prod-RAC1:Jeff-Test-VIP1:HUB,Ora-Jeff-Test-Prod-RAC2:Jeff-Test-VIP2:HUB# oracle.install.crs.config.networkInterfaceList=Bond0:10.10.164.0:1,Bond1:11.11.11.0:5# oracle.install.crs.configureGIMR=false# oracle.install.asm.configureGIMRDataDG=false# oracle.install.crs.config.storageOption=FLEX_ASM_STORAGE# oracle.install.asm.SYSASMPassword=Oracle_19C# oracle.install.crs.config.useIPMI=false# oracle.install.asm.storageOption=ASM# oracle.install.asm.diskGroup.name=OCR# oracle.install.asm.diskGroup.redundancy=NORMAL# oracle.install.asm.diskGroup.AUSize=4# oracle.install.asm.diskGroup.disksWithFailureGroupNames=/dev/asm_ocr_diska,,/dev/asm_ocr_diskb,,/dev/asm_ocr_diskc,# oracle.install.asm.diskGroup.disks=/dev/asm_ocr_diska,/dev/asm_ocr_diskb,/dev/asm_ocr_diskc# oracle.install.asm.diskGroup.diskDiscoveryString=/dev/asm*# oracle.install.asm.monitorPassword=Oracle_19C# oracle.install.asm.gimrDG.AUSize=1# oracle.install.asm.configureAFD=false# oracle.install.crs.configureRHPS=false# oracle.install.crs.config.ignoreDownNodes=false# oracle.install.config.managementOption=NONE# oracle.install.config.omsPort=0# oracle.install.crs.rootconfig.executeRootScript=falseif [ -f ${GI_HOME}/gridSetup.sh ] && [ "$(hostname)" == "$hostname1" ]; then cat >/tmp/gridsetup.rsp <<gridsetuprsporacle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_v19.0.0INVENTORY_LOCATION=$ORA_INVoracle.install.option=CRS_CONFIGORACLE_BASE=$GI_BASEoracle.install.asm.OSDBA=asmdbaoracle.install.asm.OSOPER=asmoperoracle.install.asm.OSASM=asmadminoracle.install.crs.config.scanType=LOCAL_SCANoracle.install.crs.config.gpnp.scanName=$SCANNAMEoracle.install.crs.config.gpnp.scanPort=$scanPortoracle.install.crs.config.ClusterConfiguration=STANDALONEoracle.install.crs.config.configureAsExtendedCluster=falseoracle.install.crs.config.clusterName=$cluster_nameoracle.install.crs.config.gpnp.configureGNS=falseoracle.install.crs.config.autoConfigureClusterNodeVIP=falseoracle.install.crs.config.clusterNodes=$hostname1:$VIP1NAME:HUB,$hostname2:$VIP2NAME:HUBoracle.install.crs.config.networkInterfaceList=$pub_netcard:$scan_subnet:1,$priv_netcard:$priv_subnet:5oracle.install.crs.configureGIMR=falseoracle.install.asm.configureGIMRDataDG=falseoracle.install.crs.config.storageOption=FLEX_ASM_STORAGEoracle.install.asm.SYSASMPassword=$db_admin_pwdoracle.install.crs.config.sharedFileSystemStorage.ocrLocations=oracle.install.crs.config.useIPMI=falseoracle.install.asm.storageOption=ASMoracle.install.asm.diskGroup.name=${asm_ocr_dir}oracle.install.asm.diskGroup.redundancy=NORMALoracle.install.asm.diskGroup.AUSize=4oracle.install.asm.diskGroup.disksWithFailureGroupNames=$ocr_fgsoracle.install.asm.diskGroup.disks=$ocr_diskgsoracle.install.asm.diskGroup.diskDiscoveryString=/dev/asm*oracle.install.asm.monitorPassword=$db_admin_pwdoracle.install.asm.gimrDG.AUSize=1oracle.install.asm.configureAFD=falseoracle.install.crs.configureRHPS=falseoracle.install.crs.config.ignoreDownNodes=falseoracle.install.config.managementOption=NONEoracle.install.config.omsPort=0oracle.install.crs.rootconfig.executeRootScript=falseoracle.install.crs.rootconfig.configMethod=gridsetuprsp chmod 777 /tmp/gridsetup.rsp# echo '#!/usr/bin/expect -f' >/tmp/grid_install.sh# echo "spawn su - grid -c \"${GI_HOME}/gridSetup.sh -silent -ignorePrereqFailure -responseFile /tmp/gridsetup.rsp -applyRU $RUs\"#expect {# \"*assword:\" {send \"$rootpw\r\"}#}#expect eof" >>/tmp/grid_install.sh# chmod 777 /tmp/grid_install.sh echo -e "# 开始应用rsp响应文件装置grid软件\n命令: ${GI_HOME}/gridSetup.sh -silent -ignorePrereqFailure -waitforcompletion -responseFile /tmp/gridsetup.rsp -applyRU $RUs\n响应文件内容:\n$(cat /tmp/gridsetup.rsp)" echo -e "# 开始应用rsp响应文件装置grid软件\n命令: ${GI_HOME}/gridSetup.sh -silent -ignorePrereqFailure -waitforcompletion -responseFile /tmp/gridsetup.rsp -applyRU $RUs\n响应文件内容:\n$(cat /tmp/gridsetup.rsp)" >>$logfile# expect /tmp/grid_install.sh >>$logfile su - grid -c "${GI_HOME}/gridSetup.sh -silent -ignorePrereqFailure -waitforcompletion -responseFile /tmp/gridsetup.rsp -applyRU $RUs" >>$logfile sleep 10 if [ $(tail -20 $logfile | grep orainstRoot | wc -l) -lt 1 ];then result_err "# ${GI_HOME}/gridSetup.sh -silent Failed" result_err "# ${GI_HOME}/gridSetup.sh -silent Failed" >>$logfile exit 1 else result_ok "# Grid 软件装置 ${GI_HOME}/gridSetup.sh -silent successful" result_ok "# Grid 软件装置 ${GI_HOME}/gridSetup.sh -silent successful" >>$logfile fi if [ -f $ORA_INV/orainstRoot.sh ] && [ -f $GI_HOME/root.sh ];then echo "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 执行(节点1运行) " >>$logfile sh $ORA_INV/orainstRoot.sh >>$logfile sh $GI_HOME/root.sh >>$logfile if [ $? -ne 0 ]; then result_err "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 执行(节点1运行) Failed" result_err "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 执行(节点1运行) Failed" >>$logfile exit 1 else result_ok "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 执行(节点1运行) successful" result_ok "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 执行(节点1运行) successful" >>$logfile if [ "$db_type" == "RAC" ] && [ -n $hostname2 ];then echo "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 开始执行(ssh节点2运行)" echo "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 开始执行(ssh节点2运行)" >>$logfile ssh $hostname2 $ORA_INV/orainstRoot.sh >>$logfile ssh $hostname2 $GI_HOME/root.sh >>$logfile if [ $? -ne 0 ]; then result_err "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 执行(节点2运行) Failed" result_err "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 执行(节点2运行) Failed" >>$logfile exit 1 else result_ok "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 执行(节点2运行) successful" result_ok "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 执行(节点2运行) successful" >>$logfile fi else result_err "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 节点2未运行" result_err "# $ORA_INV/orainstRoot.sh;$GI_HOME/root.sh 节点2未运行" >>$logfile exit fi fi else result_err "# $ORA_INV/orainstRoot.sh or $GI_HOME/root.sh file can not found" result_err "# $ORA_INV/orainstRoot.sh or $GI_HOME/root.sh file can not found" >>$logfile exit 1 fi if [ $? -ne 0 ]; then result_err "# grid 软件装置 Failed" result_err "# grid 软件装置 Failed" >>$logfile exit 1 else result_ok "# grid 软件装置 successful" result_ok "# grid 软件装置 successful" >>$logfile fielse result_err "# ${GI_HOME}/gridSetup.sh not found" result_err "# ${GI_HOME}/gridSetup.sh not found" >>$logfile exit 1fi# As a root user, execute the following script(s):# 1. /u01/app/oraInventory/orainstRoot.sh --> $ORA_INV/orainstRoot.sh# 2. /u01/app/19.3.0/grid/root.sh --> $GI_HOME/root.sh# # Execute /u01/app/oraInventory/orainstRoot.sh on the following nodes:# [Jeff-Test-RAC01, Jeff-Test-RAC02]# Execute /u01/app/19.3.0/grid/root.sh on the following nodes:# [Jeff-Test-RAC01, Jeff-Test-RAC02]# # Run the script on the local node first. After successful completion, you can start the script in parallel on all other nodes.# # Successfully Setup Software with warning(s).# As install user, execute the following command to complete the configuration.# /u01/app/19.3.0/grid/gridSetup.sh -executeConfigTools -responseFile /tmp/gridsetup.rsp [-silent]# 24. ASM 磁盘组增加split1 "# 24. ASM 磁盘组增加 ${asm_fra_dir} \ ${asm_data_dir}(仅节点1运行):"split1 "# 24. ASM 磁盘组增加 ${asm_fra_dir} \ ${asm_data_dir}(仅节点1运行):" >>$logfileif [ -n $fra_diskgs ]; then echo -e "# 增加 ${asm_fra_dir} 执行命令:\nsu - grid -c \"asmca -silent -sysAsmPassword $db_admin_pwd -createDiskGroup -diskString '/dev/asm*' -diskGroupName ${asm_fra_dir} -diskList '$fra_diskgs' -redundancy EXTERNAL -au_size 4\"" echo -e "# 增加 ${asm_fra_dir} 执行命令:\nsu - grid -c \"asmca -silent -sysAsmPassword $db_admin_pwd -createDiskGroup -diskString '/dev/asm*' -diskGroupName ${asm_fra_dir} -diskList '$fra_diskgs' -redundancy EXTERNAL -au_size 4\"" >>$logfile su - grid -c "asmca -silent -sysAsmPassword $db_admin_pwd -createDiskGroup -diskString '/dev/asm*' -diskGroupName ${asm_fra_dir} -diskList '$fra_diskgs' -redundancy EXTERNAL -au_size 4" >>$logfile if [ $? -ne 0 ]; then result_err "# ASM 磁盘组增加 ${asm_fra_dir}, Failed" result_err "# ASM 磁盘组增加 ${asm_fra_dir}, Failed" >>$logfile exit 1 else result_ok "# ASM 磁盘组增加 ${asm_fra_dir}, successful" result_ok "# ASM 磁盘组增加 ${asm_fra_dir}, successful" >>$logfile fielse echo "# No ${asm_fra_dir} Disk input, \$$fra_diskgs:$$fra_diskgs"fiif [ -n $data_diskgs ]; then echo -e "\n# 增加 ${asm_data_dir} 执行命令:\nsu - grid -c \"asmca -silent -sysAsmPassword $db_admin_pwd -createDiskGroup -diskString '/dev/asm*' -diskGroupName ${asm_data_dir} -diskList '$data_diskgs' -redundancy EXTERNAL -au_size 4\"" echo -e "\n# 增加 ${asm_data_dir} 执行命令:\nsu - grid -c \"asmca -silent -sysAsmPassword $db_admin_pwd -createDiskGroup -diskString '/dev/asm*' -diskGroupName ${asm_data_dir} -diskList '$data_diskgs' -redundancy EXTERNAL -au_size 4\"" >>$logfile su - grid -c "asmca -silent -sysAsmPassword $db_admin_pwd -createDiskGroup -diskString '/dev/asm*' -diskGroupName ${asm_data_dir} -diskList '$data_diskgs' -redundancy EXTERNAL -au_size 4" >>$logfile if [ $? -ne 0 ]; then result_err "# ASM 磁盘组增加 ${asm_data_dir}, Failed" result_err "# ASM 磁盘组增加 ${asm_data_dir}, Failed" >>$logfile exit 1 else result_ok "# ASM 磁盘组增加 ${asm_data_dir}, successful" result_ok "# ASM 磁盘组增加 ${asm_data_dir}, successful" >>$logfile fielse echo "# No ${asm_data_dir} Disk input, \$data_diskgs:$data_diskgs"fi# 25. DB 软件装置split1 "# 25. DB 软件装置(仅节点1运行):"split1 "# 25. DB 软件装置(仅节点1运行):" >>$logfile# $ sed -e 's/[\t ]\+$//' db_install_manual.rsp | egrep -v "^$|^#|=$"# oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v19.0.0# oracle.install.option=INSTALL_DB_SWONLY# UNIX_GROUP_NAME=oinstall# INVENTORY_LOCATION=/u01/app/oraInventory# ORACLE_BASE=/u01/app/oracle# oracle.install.db.InstallEdition=EE# oracle.install.db.OSDBA_GROUP=dba# oracle.install.db.OSOPER_GROUP=oper# oracle.install.db.OSBACKUPDBA_GROUP=backupdba# oracle.install.db.OSDGDBA_GROUP=dgdba# oracle.install.db.OSKMDBA_GROUP=kmdba# oracle.install.db.OSRACDBA_GROUP=racdba# oracle.install.db.rootconfig.executeRootScript=false# oracle.install.db.CLUSTER_NODES=ora-Jeff-Test-prod-rac1,ora-Jeff-Test-prod-rac2# oracle.install.db.config.starterdb.type=GENERAL_PURPOSE# oracle.install.db.ConfigureAsContainerDB=false# oracle.install.db.config.starterdb.memoryOption=false# oracle.install.db.config.starterdb.installExampleSchemas=false# oracle.install.db.config.starterdb.managementOption=DEFAULT# oracle.install.db.config.starterdb.omsPort=0# oracle.install.db.config.starterdb.enableRecovery=falsecat >/tmp/db_install.rsp<<dbinstoracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v19.0.0oracle.install.option=INSTALL_DB_SWONLYUNIX_GROUP_NAME=oinstallINVENTORY_LOCATION=$ORA_INVORACLE_HOME=$ORA_HOMEORACLE_BASE=$ORA_BASEoracle.install.db.InstallEdition=EEoracle.install.db.OSDBA_GROUP=dbaoracle.install.db.OSOPER_GROUP=operoracle.install.db.OSBACKUPDBA_GROUP=backupdbaoracle.install.db.OSDGDBA_GROUP=dgdbaoracle.install.db.OSKMDBA_GROUP=kmdbaoracle.install.db.OSRACDBA_GROUP=racdbaoracle.install.db.CLUSTER_NODES=$hostname1,$hostname2oracle.install.db.config.starterdb.type=GENERAL_PURPOSEoracle.install.db.isRACOneInstall=falseoracle.install.db.rac.serverpoolCardinality=0oracle.install.db.ConfigureAsContainerDB=false# oracle.install.db.config.starterdb.memoryOption=false# oracle.install.db.config.starterdb.installExampleSchemas=false# oracle.install.db.config.starterdb.managementOption=DEFAULT# oracle.install.db.config.starterdb.omsPort=0# oracle.install.db.config.starterdb.enableRecovery=falseoracle.install.db.rootconfig.executeRootScript=falseSECURITY_UPDATES_VIA_MYORACLESUPPORT=falseDECLINE_SECURITY_UPDATES=truedbinstchmod 777 /tmp/db_install.rspif [ -f $ORA_HOME/runInstaller ]; then echo -e "# 执行 DB 软件装置命令:\nsu - oracle -c \"$ORA_HOME/runInstaller -silent -force -noconfig -ignorePrereq -responseFile /tmp/db_install.rsp -applyRU $RUs\"" echo -e "# 执行 DB 软件装置命令:\nsu - oracle -c \"$ORA_HOME/runInstaller -silent -force -noconfig -ignorePrereq -responseFile /tmp/db_install.rsp -applyRU $RUs\"" >>$logfile su - oracle -c "$ORA_HOME/runInstaller -silent -force -noconfig -ignorePrereq -responseFile /tmp/db_install.rsp -applyRU $RUs" >>$logfile sleep 10 if [ $(tail -20 $logfile | grep root.sh | wc -l) -lt 1 ];then result_err "# $ORA_HOME/runInstaller -silent Failed" result_err "# $ORA_HOME/runInstaller -silent Failed" >>$logfile exit 1 else result_ok "# $ORA_HOME/runInstaller -silent successful" result_ok "# $ORA_HOME/runInstaller -silent successful" >>$logfile fi echo "# root 执行脚本 $ORA_HOME/root.sh (节点1运行)" echo "# root 执行脚本 $ORA_HOME/root.sh (节点1运行)" >>$logfile $ORA_HOME/root.sh >>$logfile if [ $? -ne 0 ]; then result_err "# root 执行脚本 $ORA_HOME/root.sh (节点1运行) Failed" result_err "# root 执行脚本 $ORA_HOME/root.sh (节点1运行) Failed" >>$logfile exit 1 else result_ok "# root 执行脚本 $ORA_HOME/root.sh (节点1运行) successful" result_ok "# root 执行脚本 $ORA_HOME/root.sh (节点1运行) successful" >>$logfile if [ "$db_type" == "RAC" ] && [ -n $hostname2 ]; then echo -e "\n# root 执行脚本 $ORA_HOME/root.sh (节点2运行)" echo -e "\n# root 执行脚本 $ORA_HOME/root.sh (节点2运行)" >>$logfile $ORA_HOME/root.sh >>$logfile fi fi if [ $? -ne 0 ]; then result_err "# DB 软件装置 Failed" result_err "# DB 软件装置 Failed" >>$logfile exit 1 else result_ok "# DB 软件装置 successful" result_ok "# DB 软件装置 successful" >>$logfile fielse result_err "# $ORA_HOME/runInstaller file not found" result_err "# $ORA_HOME/runInstaller file not found" >>$logfile exit 1fi# 26. DBCA 创立数据库split1 "# 26 DBCA 创立数据库(仅节点1运行):"split1 "# 26 DBCA 创立数据库(仅节点1运行):" >>$logfile# $ sed -e 's/[\t ]\+$//' dbca_MANUAL.rsp | egrep -v "^$|^#|=$"# responseFileVersion=/oracle/assistants/rspfmt_dbca_response_schema_v12.2.0# gdbName=JeffTest# sid=Jeff0# databaseConfigType=RAC# policyManaged=false# createServerPool=false# force=false# createAsContainerDatabase=true# numberOfPDBs=1# pdbName=Jeff_pdb# useLocalUndoForPDBs=true# nodelist=jeff-test-rac01,jeff-test-rac02# templateName=/u01/app/oracle/product/19.3.0/db_1/assistants/dbca/templates/New_Database.dbt# emExpressPort=5500# runCVUChecks=TRUE# omsPort=0# dvConfiguration=false# olsConfiguration=false# datafileJarLocation={ORACLE_HOME}/assistants/dbca/templates/# datafileDestination=+DATA/{DB_UNIQUE_NAME}/# recoveryAreaDestination=+FRA# storageType=ASM# diskGroupName=+DATA/{DB_UNIQUE_NAME}/# recoveryGroupName=+FRA# characterSet=AL32UTF8# nationalCharacterSet=UTF8# registerWithDirService=false# skipListenerRegistration=true# variables=ORACLE_BASE_HOME=/u01/app/oracle/product/19.3.0/db_1,DB_UNIQUE_NAME=JeffTest,ORACLE_BASE=/u01/app/oracle,PDB_NAME=,DB_NAME=Jeff,ORACLE_HOME=/u01/app/oracle/product/19.3.0/db_1,SID=Jeff0# initParams=Jeff01.undo_tablespace=UNDOTBS1,Jeff02.undo_tablespace=UNDOTBS2,enable_pluggable_database=true,sga_target=1824MB,db_block_size=8192BYTES,cluster_database=true,standby_file_management=AUTO,family:dw_helper.instance_mode=read-only,log_archive_dest_1='LOCATION=+FRA',nls_language=AMERICAN,filesystemio_options=SETALL,dispatchers=(PROTOCOL=TCP) (SERVICE=Jeff0XDB),diagnostic_dest={ORACLE_BASE},remote_login_passwordfile=exclusive,db_create_file_dest=+DATA/{DB_UNIQUE_NAME}/,db_create_online_log_dest_2=+FRA,db_create_online_log_dest_1=+DATA,nls_date_format="YYYY/MM/DD HH24:MI:SS",parallel_force_local=TRUE,audit_file_dest={ORACLE_BASE}/admin/{DB_UNIQUE_NAME}/adump,processes=5000,pga_aggregate_target=609MB,Jeff01.thread=1,Jeff02.thread=2,nls_territory=AMERICA,undo_retention=10800,session_cached_cursors=200,local_listener=-oraagent-dummy-,db_recovery_file_dest_size=18000MB,db_unique_name=JeffTest,optimizer_adaptive_plans=FALSE,open_cursors=1000,control_file_record_keep_time=31,log_archive_format=arch_%t_%s_%r.arc,compatible=19.0.0,sga_max_size=1000MB,db_name=Jeff,archive_lag_target=1800,result_cache_max_size=0MB,db_files=2000,enable_ddl_logging=TRUE,Jeff01.instance_number=1,Jeff02.instance_number=2,db_recovery_file_dest=+FRA,audit_trail=db# sampleSchema=false# memoryPercentage=40# databaseType=MULTIPURPOSE# automaticMemoryManagement=false# totalMemory=0cat >/tmp/dbca.rsp<<dbcarspresponseFileVersion=/oracle/assistants/rspfmt_dbca_response_schema_v12.2.0gdbName=$DB_UNIQUE_NAMEsid=$ORA_SID_PREFIXdatabaseConfigType=RACRACOneNodeServiceName=policyManaged=falsecreateServerPool=falseforce=falsecreateAsContainerDatabase=truenumberOfPDBs=1pdbName=$PDB_SIDuseLocalUndoForPDBs=truepdbAdminPassword=$ORAPWDnodelist=$hostname1,$hostname2templateName=$ORA_HOME/assistants/dbca/templates/New_Database.dbtsysPassword=$ORAPWDsystemPassword=$ORAPWDserviceUserPassword=$ORAPWDemConfiguration=emExpressPort=5500runCVUChecks=TRUEdbsnmpPassword=$ORAPWDomsPort=0dvConfiguration=falseolsConfiguration=falsedatafileJarLocation={ORACLE_HOME}/assistants/dbca/templates/datafileDestination=+${asm_data_dir}/{DB_UNIQUE_NAME}/recoveryAreaDestination=+${asm_fra_dir}storageType=ASMdiskGroupName=+${asm_data_dir}/{DB_UNIQUE_NAME}/asmsnmpPassword=$ORAPWDrecoveryGroupName=+${asm_fra_dir}characterSet=AL32UTF8nationalCharacterSet=UTF8registerWithDirService=falseskipListenerRegistration=truevariables=ORACLE_BASE_HOME=$ORA_HOME,DB_UNIQUE_NAME=$DB_UNIQUE_NAME,ORACLE_BASE=$ORA_BASE,PDB_NAME=$PDB_SID,DB_NAME=$DB_NAME,ORACLE_HOME=$ORA_HOME,SID=$ORA_SID_PREFIXinitParams=$ORA_SID1.undo_tablespace=UNDOTBS1,$ORA_SID2.undo_tablespace=UNDOTBS2,enable_pluggable_database=true,sga_target=$sgasize,db_block_size=8192BYTES,cluster_database=true,standby_file_management=AUTO,family:dw_helper.instance_mode=read-only,log_archive_dest_1='LOCATION=+${asm_fra_dir}',nls_language=AMERICAN,filesystemio_options=SETALL,dispatchers=(PROTOCOL=TCP) (SERVICE=${ORA_SID_PREFIX}XDB),diagnostic_dest={ORACLE_BASE},remote_login_passwordfile=exclusive,db_create_file_dest=+${asm_data_dir}/{DB_UNIQUE_NAME}/,db_create_online_log_dest_2=+${asm_fra_dir},db_create_online_log_dest_1=+${asm_data_dir},nls_date_format="YYYY/MM/DD HH24:MI:SS",parallel_force_local=TRUE,audit_file_dest={ORACLE_BASE}/admin/{DB_UNIQUE_NAME}/adump,processes=$processes,pga_aggregate_target=$pgasize,$ORA_SID1.thread=1,$ORA_SID2.thread=2,nls_territory=AMERICA,undo_retention=10800,session_cached_cursors=200,local_listener=-oraagent-dummy-,db_recovery_file_dest_size=$recovery_size,db_unique_name=$DB_UNIQUE_NAME,optimizer_adaptive_plans=FALSE,open_cursors=1000,max_dump_file_size='1024m',control_file_record_keep_time=31,log_archive_format=arch_%t_%s_%r.arc,compatible=19.0.0,sga_max_size=$sga_max_size,db_name=$DB_NAME,archive_lag_target=1800,result_cache_max_size=0MB,db_files=2000,enable_ddl_logging=TRUE,$ORA_SID1.instance_number=1,$ORA_SID2.instance_number=2,db_recovery_file_dest=+${asm_fra_dir},audit_trail=dbsampleSchema=falsememoryPercentage=40databaseType=MULTIPURPOSEautomaticMemoryManagement=falsetotalMemory=0dbcarspchmod 777 /tmp/dbca.rspif [ $needcdb != "y" ] && [ $needcdb != "Y" ];then echo "# Do not need CDB" sed -i 's/createAsContainerDatabase=true/createAsContainerDatabase=false/g' /tmp/dbca.rsp if [ $needpdb != "y" ] && [ $needpdb != "Y" ];then sed -i "s/numberOfPDBs=1/numberOfPDBs=0/g" /tmp/dbca.rsp sed -i "s/PDB_NAME=$PDB_SID,//g" /tmp/dbca.rsp sed -i "/PDB_NAME=$PDB_SID/d" /tmp/dbca.rsp fificat /tmp/dbca.rsp >>$logfileecho "# 开始 DBCA 建库"echo "# 开始 DBCA 建库" >>$logfilesu - oracle -c "dbca -silent -createDatabase -ignorePrereqFailure -responseFile /tmp/dbca.rsp -redoLogFileSize 200 -useOMF true -enableArchive true -emConfiguration NONE"if [ $? -ne 0 ];then result_err "# DBCA 建库失败,Failed" result_err "# DBCA 建库失败,Failed" >>$logfile exit 1else result_ok "# DBCA 建库胜利,successful" result_ok "# DBCA 建库胜利,successful" >>$logfilefi

March 16, 2023 · 28 min · jiezi

关于bash:shell-命令提示符中显示时间qbit

前言本文对 Ubuntu 20.04 实用bashbash 版本 5.0.17配置 export PS1="\u@\h: \$PWD/ \D{%Y-%m-%d} \t\n$ "后果 qbit@qhost: /home/qbit/ 2023-02-16 17:13:22$ dateThu 16 Feb 2023 05:13:23 PM CST能够将上述配置加到 .bashrc 中fish编辑文件 ~/.config/fish/functions/fish_prompt.fish (目录或文件不存在就新建),模板参照 /usr/share/fish/functions/fish_prompt.fish function fish_prompt if not set -q __fish_prompt_hostname set -g __fish_prompt_hostname (hostname) end set_color -o cyan echo -n -s "$USER" @ "$__fish_prompt_hostname" ": " set_color -o green echo -n (prompt_pwd) echo -n ' ' echo -n (date +"%Y-%m-%d %H:%M:%S" ) echo '' echo -n "\$ " set_color normalendfish 的 ~/.config/fish/config.fish 对标 bash 的 .bashrc编辑 ~/.config/fish/config.fish 显示残缺门路 ...

February 16, 2023 · 1 min · jiezi

关于bash:TIL-在-Finder-中打开-iOS-模拟器的文件系统

分享两个脚本用于关上 iOS simulator 的设施文件系统与特定 App 的文件系统 设施文件系统设施文件系统是指从 simulator 的“文件”利用中的 On My iPhone 这里看到的文件: open "`xcrun simctl get_app_container booted com.apple.DocumentsApp groups | grep LocalStorage | awk -F'\t' '{print $2}'`/File Provider Storage" -a Finder运行即可: App 文件系统是指每个 App 本人独立的文件系统。 #!/bin/bashPACKAGE_NAME="${1:-default.package.name}" # 默认值open `xcrun simctl get_app_container booted $PACKAGE_NAME data` -a Finder保留为脚本文件,加执行权限,执行: ./sim-app-fs.sh your.package.name 不想保留脚本文件就把 $PACKAGE_NAME 替换成理论的包名间接执行。 补充阐明xcrun simctl 仿佛有 bug cli 帮忙信息里说能够指定特定的 group identifier 来获取指定 group 的门路:但实际上如果指定了 identifier 会认为是谬误的参数,还是打印帮忙信息:这货色也没有官网文档,网上一个用 identifier 的例子都找不到,十有八九是 bug 了倡议配合 raycast 这类工具应用脚本,体验很好 ...

January 31, 2023 · 1 min · jiezi

关于bash:详细说明bashprofile文件

bash的环境配置文件获得bash时须要残缺的登录流程,简称login shell。login shell个别只读取两个配置文件: /etc/profile :零碎整体的设置~/.bash_profile或~/.bash_login或~/.profile:用户集体设置/etc/profile每个用户登录获得bash,肯定会读取的配置文件。不倡议批改 该文件设置的次要变量: PATH:依据UID决定PATH变量要不要含有sbin的系统命令目录MAIL:依据账户设置好的用户的mailbox到/var/spool/mail账户名USER:依据用户的账户设置此变量内容HOSTNAME:依据主机的hostname命令决定此变量内容HISTSIZE:历史命令记录条数umask:包含root默认为022,而个别用户为002等并且默认依序调用以下文件: /etc/profile.d/*.sh:/etc/profile.d目录下sh后缀的问价都会被执行,该目录下次要标准了bash界面的色彩、语系、ll与ls命令的别名、which别名、vi别名等/etc/locale.conf:这个文件由/etc/profile.d/lang.sh调用,决定了bash默认应用那个语系,其中最重要的是LANG/LC_ALL这个变量的设置/usr/share/bash-completion/completiopns/*:命令补全、文件名补全、命令的选项/参数补全,由/etc/profile.d/bash_completyion.sh文件加载执行~/.bash_profilelogin shell的bash环境时候,只会执行上面三个文件中的其中一个,依序 ~/.bash_profile~/.bash_login~/.profile如果~/.bash_profile这个不存在,才会读取~/.bash_login。 .bash_profileGet the aliases and functionsif [ -f ~/.bashrc ]; then. ~/.bashrcfi User specific environment and startup programsexport PS1="[\u@\h \w]&dollar; " set Java environmentJAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.45.x86_64[JACOCO_COMMENT]JAVA_HOME=/xxxx/jdk7export JAVA_HOME=/home/xxoo/jacoco/jdk/jdk7PATH=$JAVA_HOME/bin:$PATHCLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jarexport JAVA_HOMEexport PATHexport CLASSPATHalias l='ls -ltr --color=none'alias ls='ls --color=none'alias cls="clear"export JACOCO_AGENT_JAR_PATH=/home/xxoo/jacoco/jacoco/jacoco-0.8.1-rel/lib/jacocoagent.jar 该文件第三行的if语句是判断是否存在~/.bashrc文件,若存在就读入~/.bashrc文件的配置。读取bash的配置文件(~/.bashrc等),次要通过命令source读取。 对于jacoco次要是上面两个全局变量: export JAVA_HOME=/home/xxoo/jacoco/jdk/jdk7export JACOCO_AGENT_JAR_PATH=/home/xxoo/jacoco/jacoco/jacoco-0.8.1-rel/lib/jacocoagent.jarJAVA_HOME:设置零碎java命令为jacoco目录下的java,其中jacoco下的java是一个脚本文件JACOCO_AGENT_JAR_PATH:应用java启动利用时候增加的一个参数其余配置文件: ~/.bash_history:默认状况下,历史命令记录在这个文件外面,记录条数则与变量HISTSIZE变量无关,每次登陆bash,bash会读取这个文件,并且把所有历史命令读入到内存。~/.bash_logout:这个问价次要是【当你登记bash后,零碎帮你做完什么操作才来到】,默认状况是清理屏幕信息,也能够吧一些备份或者重要的工作写在这个文件外面(清理缓存)。参考链接:Understanding bash_profile file in Linux

July 19, 2022 · 1 min · jiezi

关于bash:Bash终端快捷键

Bash快捷键解析Bash提供了许多应用的快捷键操作,可能在实际操作终端命令行是极大提高效率。这些快捷方式终端对GUN Readline库的依赖关系实现的。一旦你用惯了这些快捷键,就能疾速执行一些命令,而不必在键盘上大幅度的挪动。这些快捷键分为几类:导航快捷键、文本输出快捷键、命令历史快捷键和其余快捷键。 导航快捷键利用左箭头和右键头在一行中向前或向后挪动是十分常见的,不过还有其余一些选项也能够让你不必把手从“home”键上挪开。 快捷键 动作Ctral+a 将光标移到本行的开始处Ctrl+e 将光标移到本行的结尾处Ctrl+b(或左箭头键) 将光标回退一个字符Ctrl+f(或右箭头键) 将光标后退一个字符文本输出快捷键每个人都晓得用Backspace键能够删除前一个字符,但手指要挪动肯定的间隔才可能到这个按键,并且它一次只能删除一个字符,而应用快捷键能够疾速的删除整行文本。 快捷键 动作Ctrl+d 删除后一个字符Ctrl+u 从行的结尾剪切至行的开端Ctrl+y yank(即粘帖)之前剪切的文本Ctrl+t transpose(即替换)前两个字符地位Backspace键 删除前一个字符Ctrl+k 从光标开始剪切至行的开端命令历史快捷键快捷键 动作Ctrl+p(或向上箭头) 获取前一个历史命令Ctrl+n(或向下箭头) 获取后一个历史命令Ctrl+r 对历史命令的反向搜寻反向搜寻命令在理论应用中特地有用。如果咱们想要从新执行几天应用过的一个命令,然而只依稀记得命令中的个别重要单词,那么反向搜寻就能派上用途。参考链接:Bash Shortcuts Every Linux User Needs to Know

July 5, 2022 · 1 min · jiezi

关于bash:shell脚本编程学习笔记运算符

shell波及数字计算的理论场景感觉绝对较少,更多场景是关系运算。bash也不提供数字计算能力,须要通过expr实现。这里简略记录expr罕用数字计算形式,其余篇幅具体记录关系运算。 数字计算expr 是表达式计算工具,用于实现表达式的求值操作。 a=1b=2# ``操作符用于运行外部的表达式并返回执行后果sum=`expr ${a} + ${b}`# $()操作符与``性能一样。理论场景中举荐只应用其中一种。diff=$(expr ${b} - ${a})# mac中 expr 能够应用 $(()) 代替diff=$((${b} - ${a}))expr罕用运算符:加(+),减(-),乘(*),除(/),取余(%)。其中 * 为保留字,应用时须要转译:expr 2 /* 2 关系运算shell中应用较多的场景之一就是if-else判断。shell提供了几种模式 if testif []if [[]]

June 20, 2022 · 1 min · jiezi

关于bash:利器-Terminal-Shell-改造记录-Windows-Terminal-Oh-My-ZSH-Tmux

“利器”系列阐明:“工欲善其事必先利其器”,有了称手好用的工具,能力最大水平施展出本人的能力,进步生产力和效率,防止有效加班。因而,“利器”系列将会记录我对于各种工具的革新,以及我是如何组合利用它们施展价值。 这篇文章次要记录我 Terminal & Bash 革新,Terminal & Bash 是所有程序员在新的开发环境下第一个接触也是最常接触的中央,因而,这里的作为“利器”系列的第一篇,分享给大家。 注:以下内容中,波及到下载的链接,均曾经过国内网络优化地址,不便大家疾速下载 Terminal :Windows TerminalWindows环境下,我抉择 Windows Terminal 抉择起因:其余的 Terminal 存在一个不好解决的问题,就是在应用近程Tmux的状况下,无奈应用鼠标抉择复制粘贴,同时Windows Terminal 也领有不输其余 Terminal 个性化配置性能 装置办法:间接在微软利用商店搜寻“Windows Terminal”装置即可。 配置有两种配置形式,一种是交互式,另一种是编辑配置文件setttings.json,倡议首次配置应用交互式的配置形式即可。配置实现后,能够将配置文件导出备份到云盘上,不便当前间接应用。 我次要批改了字体和字号,字号设置为14,不便大屏幕浏览,字体用的是“FiraCode”,这是一种针对于编程的字体,具体的介绍能够看这里:FiraCode 字体的官网下载链接:FiraCode.zip 阿里云下载链接: 「firacode」,点击链接保留,或者复制本段内容,关上「阿里云盘」APP ,无需下载极速在线查看,视频原画倍速播放。 链接:https://www.aliyundrive.com/s...Shell 配置因为我个别都是在本地通过SSH近程连贯到服务器Ubuntu零碎上,因而,这里只探讨Ubuntu环境下的Shell配置。 装置 ZSH在Ubuntu零碎下,执行 sudo apt install -y zsh curl wget git tmux装置 Oh My ZshOh My Zsh 是 Zsh 的配置管理器,包含插件,主题等的配置,并且曾经默认了许多实用功能,集成了相当多的插件(大部分默认不启用)有趣味的敌人能够进入它的官网获取更多信息: Oh My Zsh - a delightful & open source framework for Zsh 想疾速理解的敌人,能够看看它的Cheatsheet: https://github.com/ohmyzsh/ohmyzsh/wiki/Cheatsheet 装置过程 cd ~wget https://pd.zwc365.com/https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh# 设置远端地址为github镜像地址Export REMOTE=https://hub.fastgit.org/ohmyzsh/ohmyzsh.gitsh install.sh装置 starshipsh -c "$(curl -fsSL https://pd.zwc365.com/https://starship.rs/install.sh)" -- -B https://hub.fastgit.org/starship/starship/releasesecho 'eval "$(starship init zsh)"' >> ~/.zshrc装置 Shell 语法高亮插件插件地址: ...

November 28, 2021 · 1 min · jiezi

关于bash:学点bash装B-快速移动光标

学点bash,装B the-art-of-command-line ctrl-w 删除你键入的最初一个单词 ctrl-u 删除行内光标所在位置之前的内容 ctrl-k 删除光标至行尾的所有内容 ctrl-l 能够清屏 ctrl-a 能够将光标移至行首 ctrl-e 能够将光标移至行尾 option-b 和 option-f 能够以单词为单位挪动光标 若按单词挪动生效,请按文章疏导配置 焦虑的头发都要掉了,尝试扭转下本人原文地址

October 21, 2021 · 1 min · jiezi

关于bash:Bash-笔记

<meta charset="utf-8" emacsmode="-*- markdown -*-"> <link rel="stylesheet" href="https://casual-effects.com/markdeep/latest/journal.css?"> 本文有多个主题: SHell 代码的实质成对符、结尾符、退出码,和一些习惯玩玩并行各个主题互相独立,可间接跳到你想看的那个。 SHell 代码的实质有句话说是, Bash 上所有皆字符串。 猜想起因: Bash 是被造出来用来兼顾 Linux (或者别的类 *nix 零碎)的过程交互合作的,而过程间通信时所用数据的类型肯定是字符串。 示例: 上面几行的意义是齐全一样的 echo aecho 'a'echo "a"echo \a这里 a 自身就是个别字符串了,所以不论是用引号打消性能还是用本义打消性能,它都依然是个别字符。 上面几行的意义是齐全一样的 echo 'foo bar'echo "foo bar"echo foo' 'barecho foo" "barecho foo\ \ bar上面几行的意义是齐全一样的 v1=foo v2=ar ; echo $v1\ \ b$v2v3=\ \ ; echo foo"$v3"barv4=' ' ; echo foo"$v4"bar如果下面的 v3 v4 都是只有一个空格字符串而不是像下面那样是两个的话,应用时就能够不用被双引号突围,就像这样: v5=\ ; echo foo${v5}bar 大括号能够清晰形容变量名的边界。没有歧义的时候能够省略大括号。 上面几行是意义齐全一样的 bash -c 'echo foo\ \ bar'bash -c "echo foo\ \ bar"bash -c 'echo foo" "bar'bash -c "echo foo' 'bar"v=' ' ; bash -c "echo foo'$v'bar"上面几行是意义齐全一样的(我感觉这是比拟能体现「所有皆字符串」的中央) ...

October 20, 2021 · 3 min · jiezi

关于bash:研发环境手册

前言拿到新设施的第一天,配置环境总结。实用于: 设施环境:macOS研发前端开发(步骤5、6、7)注释首先,装置homebrew官网地址:https://brew.sh/index_zh-cn官网shell: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"国内镜像:https://www.cnblogs.com/liyih...国内shell【举荐】: /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"注意事项: 装置过程中设施呈现装置命令行工具的弹窗,须要等装置完命令行工具之后再持续进行。只用国内镜像源会快很多二 装置git【依赖homebrew】brew install git配置: git config —global user.name "user-name"git config —global user.email "user-email"三 装置item2下载地址: https://iterm2.com/downloads.... 四 装置zsh官网地址: https://ohmyz.sh/#install官网shell: sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"举荐shell: sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"五 装置nvm地址: https://github.com/nvm-sh/nvm先应用cur 来装置,如果装置失败则应用git clone 办法来装置最初须要配置环境变量到对应的配置文件上 六 装置node【依赖nvm】nvm install node #默认装置最新版本node七 装置nrm (镜像源管理工具)npm -g install nrm

September 29, 2021 · 1 min · jiezi

关于bash:在bash中从一个文件中读取文件名称并检查当前目录是否保护这些文件

目标:在bash中从一个文件中读取文件名称,并查看当前目录下的所有文件,若不存在则返回提醒实现:check_file.sh #!/bin/bash# 获取以后门路CRTDIR=$(pwd)i=0# 从保留了文件名称的txt文件中获取文件名,并生成数组for line in $(cat filelist.txt)do file_list[$i]=${line%%[[:cntrl:]]} ((i++))done# 查看数组中的文件是否存在于当前目录及所有的子目录下for FILE in "${file_list[@]}"do file_count=$(find $CRTDIR -name $FILE | wc -l) if [[ $file_count -eq 0 ]] then echo "Warning: $FILE not found in $CRTDIR!" fidone应用: 将check_file.sh与filelist.txt两个文件放到须要查看的目录下Windows零碎下,能够用Git Bash,先转到该目录输出./check_file.sh, 运行脚本例子: # file.txt1.pdf2.cad3.txt4.exe// 目录构造BashTest├─ 1│ └─ 3.txt├─ check_file.sh└─ filelist.txt$ ./check_file.shWarning: 1.pdf not found in /g/BashTest!Warning: 2.cad not found in /g/BashTest!Warning: 4.exe not found in /g/BashTest!人能常清静,天地悉皆归

July 3, 2021 · 1 min · jiezi

关于bash:For-loop-in-bash

10 Bash for Loop In One Line ExamplesBash For Loop Examples In LinuxWhat Is Bash in Linux? Bash for Loop In one Line with items# for i in 1 2 3 4 5 ; do echo "$i" ; done# for i in {1..5} ; do echo "$i" ; done# for i in {1..5..1};do echo "$i" ; done# for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus; do echo $planet; doneBash for loop C style In One Line with items# for ((i=1;i<=5;i++));do echo $i;doneBash For Loop In one line with Command Output# for i in `seq 1 5`;do echo $i ;done# for i in `cat test`;do dig $i +short ;done# for i in `awk '{print $1}' test` ;do ping -c 2 $i ;doneBash For Loop In one Line with variables# for i in $(cat test);do dig $i +short ;done# a="a b c"# for i in $a;do echo $i;doneabc# a=(a b c)# for i in ${a[@]};do echo $i;doneabc# for i in $(seq 1 5);do echo $i ;doneBash For Infinite Loop In one Line# for (( ; ; )); do echo "Hello World!"; done# while true; do echo "Hello World!"; done# while :; do echo "Hello World!"; doneBash For Loop In One Line with Files# for i in *; do echo "Found the following file: $i"; done# for i in `cat filelist.txt`; do echo ${i}; done;if a line may include spaces better use a while loop:# cat filelist.txt | while read LINE; do echo "${LINE}"; done10 Bash for Loop In One Line ExamplesBash For Loop Examples In LinuxWhat Is Bash in Linux? ...

June 13, 2021 · 2 min · jiezi

关于bash:for-循环与位置参数

word splitting(分词)如果没有在双引号中,变量在进行参数扩大、命令替换和算术扩大之后,shell 会对变量进行分词,比方: $ echo a b c da b c dshell 将 $IFS 的每个字符作为分隔符,如果 $IFS 是 unset 的,则有默认值 <space><tab><newline>。 分词的时候,首先疏忽变量首位的空白符 <space><tab><newline>,再分隔失去单词。 判断 $IFS 是否 unset 的办法。 // 文件test#!/usr/bin/bashif [ -v IFS ];then echo ==\$IFS=$IFS==else echo ==\$IFS is unset==fi$ ./test==$IFS= ==for 循环中的 $* 与 $@$* 与 $@ 都能示意所有的地位参数。 未在双引号中:二者用法统一,都会进行分词。 // 文件test#!/usr/bin/bashecho '==$*=='for name in $*doecho $namedoneecho '==$@=='for name in $@doecho $namedone$ ./test a s d fff==$*==asdfff==$@==asdfff在双引号中:$* 会先分词,再以 $IFS 的第一个字符为分隔符,合并成一个字符串; "$*" 相当于 "$1c$2c…",c 示意 $IFS 的第一个字符。 ...

May 29, 2021 · 1 min · jiezi

关于bash:ifuntilwhile中的testcommands

exit status上一个命令执行完后,退出时返回的状态值。 0 示意胜利;非0示意失败。 在命令行中能够打印查看上一个状态值 $ echo $?依赖于 exit status 的 if、until、whileuntil 的语法: until test-commands; do consequent-commands; donewhile 的语法 while test-commands; do consequent-commands; doneif 的语法 if test-commands; then consequent-commands;[elif more-test-commands; then more-consequents;][else alternate-consequents;]fitest-commands 执行之后,if、until、while 依赖于它的 exit status: 为 0 时,if 执行;为 1 时,until 执行;为 0 时,while 执行。test-commands 蕴含的状况一组或多组管道组成 test-commands多组管道之间能够由 ;, &, &&, 或 ||分隔,由 ;, &, 或 换行 完结;exit status 由最初一组管道的 exit status 决定;一个或多个命令组成一个管道,由| 或 |& 分隔,由最初一个命令的 exit status 决定管道的 exit status;一般而言,单个命令执行胜利,状态值为0。 ...

May 29, 2021 · 1 min · jiezi

关于bash:bash-字符串

\ 反斜杠(本义)紧跟着的 \ 的字符字面量会被保留,输入的时候去掉 \。 一个特例是 \newline (反斜杠+换行符),这个组合会被当做长字符串换行,输入的时候将 \newline (反斜杠+换行符)移除、疏忽。 $ echo \aa$ echo \aaaaaa$ echo aaa\> ssssaaassss'' 单引号无奈应用本义 $ echo 'aaa'aaa"" 双引号根本作用:保留字面量 特例: '$': # $name 援用变量名$ test=asdfg$ echo "$test"asdfg$ echo "11${test}22"11asdfg22# $(command) 执行命令,将后果扩大为字符串$ echo "aaaa$(ls)ssss"aaaa1.txt2.txtssss# $(( expression )) 执行算术表达式,将后果扩大为字符串$ echo "aaaa$(( 3+4 ))ssss"aaaa7ssss'`': # `command` 执行命令,将后果扩大为字符串$ echo "aaaa`ls`ssss"aaaa1.txt2.txtssss'\': # 反斜杠+一般字符$ echo "\a"\a# '$', '`', '"', '\', or 'newline'(换行)# 反斜杠+以上几个特殊符号,输入的时候反斜杠会被删除;其中,`newline` 也会被删除$ echo "\$\`\"==\> =="$`"====# 不论开启或者敞开历史扩大的性能,`反斜杠+!`的输入都同 `反斜杠+一般字符` 一样$ echo "\!-1"\!-1history expansion 开启时,'!': ...

May 29, 2021 · 1 min · jiezi

关于bash:exec-c-及-ENVSUPATH

验证问题以及发现问题验证 manual page 中 exec -c command 不会开启新过程,但环境变量为空。验证形式:打印过程id echo $BASHPID打印环境变量PATH echo $PATH打印所有环境变量 export -p // 文件 test1#!/usr/bin/bashset -e./test2// 文件 test2#!/usr/bin/bashset -eecho '2==PID='$BASHPIDecho '2==PPID='$PPIDecho '2==PATH='$PATHecho '2==export=='`export -p`exec -c ./test3// 文件 test3#!/usr/bin/bashset -eecho '3==PID='$BASHPIDecho '3==PPID='$PPIDecho '3==PATH='$PATHecho '3==export='`export -p`//执行 $ ./test12==PID=286972==PPID=286962==PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin2==export==declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus" declare -x HOME="用户主目录" declare -x LANG="en_US.UTF-8" declare -x LC_TERMINAL="iTerm2" declare -x LC_TERMINAL_VERSION="3.3.8" declare -x LESSCLOSE="/usr/bin/lesspipe %s %s" declare -x LESSOPEN="| /usr/bin/lesspipe %s" declare -x LOGNAME="登录用户" declare -x LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.webp=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:" declare -x MOTD_SHOWN="pam" declare -x OLDPWD="用户目录" declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" declare -x PWD="当前目录名" declare -x SHELL="/bin/bash" declare -x SHLVL="3" declare -x SSH_CLIENT="192.168.0.101 51426 22" declare -x SSH_CONNECTION="192.168.0.101 51426 192.168.0.121 22" declare -x SSH_TTY="/dev/pts/0" declare -x TERM="xterm-256color" declare -x USER="用户名" declare -x XDG_DATA_DIRS="/usr/local/share:/usr/share:/var/lib/snapd/desktop" declare -x XDG_RUNTIME_DIR="/run/user/1000" declare -x XDG_SESSION_CLASS="user" declare -x XDG_SESSION_ID="204" declare -x XDG_SESSION_TYPE="tty"3==PID=286973==PPID=286963==PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin3==export=declare -x OLDPWD declare -x PWD="当前目录名" declare -x SHLVL="1"察看输入test2 同 test3 的过程id、父过程id雷同,后者的环境变量(export -p)能够看做为空(PWD 是当前目录名,SHLVL 是 shell 深度)。 ...

May 29, 2021 · 1 min · jiezi

关于bash:前端面试每日-31-第704天

明天的知识点 (2021.03.20) —— 第704天 (我也要出题)[html] 在微信的H5页面不能下载如何解决?[css] word-spacing有什么作用?[js] 写一个办法在肯定工夫内无任何操作时执行某个事件[软技能] 你有本人写过bash脚本吗?都有写过哪些脚本?《论语》,曾子曰:“吾日三省吾身”(我每天屡次检查本人)。前端面试每日3+1题,以面试题来驱动学习,每天提高一点!让致力成为一种习惯,让奋斗成为一种享受!置信 保持 的力量!!!欢送在 Issues 和敌人们一起探讨学习! 我的项目地址:前端面试每日3+1【举荐】欢送跟 jsliang 一起折腾前端,零碎整顿前端常识,目前正在折腾 LeetCode,打算买通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个Star, 同时欢送微信扫码关注 前端剑解 公众号,并退出 “前端学习每日3+1” 微信群互相交换(点击公众号的菜单:交换)。 学习不打烊,充电加油只为遇到更好的本人,365天无节假日,每天早上5点纯手工公布面试题(死磕本人,愉悦大家)。心愿大家在这虚夸的前端圈里,放弃沉着,保持每天花20分钟来学习与思考。在这变幻无穷,类库层出不穷的前端,倡议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢送大家到Issues交换,激励PR,感激Star,大家有啥好的倡议能够加我微信一起交换探讨!心愿大家每日去学习与思考,这才达到来这里的目标!!!(不要为了谁而来,要为本人而来!)交换探讨欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个[Star]

March 20, 2021 · 1 min · jiezi

关于bash:获取脚本自身路径

在写 gar 脚本的时候,我须要在 gar 脚本在运行时确定它本身在文件系统中所处目录的门路。基于该门路,可将 gar.css 文件部署到文档我的项目的根目录下,因为 gar.css 与 gar 脚本在同一目录下,后者须要依据本身的地位方能找到它,否则就只能由 gar 脚本的用户提供 gar.css 的门路,有所不便。 BASH_SOURCE有人说,用以下语句可取得脚本本身门路 my_path=$(cd $(dirname "BASH_SOURCE[0]") && pwd)我思考了一会。真的思考了……甚至还看了看 Bash reference manual 里对 BASH_SOURCE 的形容: 这个形容里有 FUNCNAME,我又在 manual 里找到了以下形容: 谁晓得它们在说什么呢?目前,我只晓得 BASH_SOURCE 是个数组变量,存储了一组源文件名(Source filename)。百闻不如一见,我须要 echo 一下 ${BASH_SOURCE[0]}: #!/bin/bashecho ${BASH_SOURCE[0]}我将上述脚本取名为 foo,将其置于我定义的一个专用于寄存脚本的目录内,并赋其可执行权限,而后执行 foo, $ foo/home/garfileo/.my-scripts/foo换一种形式执行 foo, $ bash /home/garfileo/.my-scripts/foo/home/garfileo/.my-scripts/foo再换一种形式, $ bash $(foo)/home/garfileo/.my-scripts/foo再换一种形式, $ source $(foo)/home/garfileo/.my-scripts/foo在 Bash 的语法里,$(...) 称为命令替换,即开拓一个子 Shell,在其中执行括号内的命令,并以文本的模式返回后果。 上述试验揭示的是,foo 脚本在运行时,能够确定本人身处何处。foo 能够,gar 也能够。 BASH_SOURCE[0] 与 $0 有什么区别?仿佛通过命令行的第一个参数 $0 也能令一个脚本获知本身所处地位。将 foo 改为 ...

March 16, 2021 · 2 min · jiezi

关于bash:身在何处

我是 Gar,我想讲一下我本人。我想了好几个结尾,最初决定先从确定本人身在何处讲起。 BASH_SOURCE一开始,我不晓得本人身在何处,为此寻访天下。有人山盟海誓,说我在 $(cd $(dirname "BASH_SOURCE[0]") && pwd)我思考了一会。真的思考了……甚至还看了看 Bash reference manual 里对 BASH_SOURCE 的形容: 这个形容里有 FUNCNAME,我又在 manual 里找到了以下形容: 然而我和你一样,思考的是,谁晓得它们在说什么呢?目前,我只晓得 BASH_SOURCE 是个数组变量,存储了一组源文件名(Source filename)。 百闻不如一见,我要 echo 一下 ${BASH_SOURCE[0]}: #!/bin/bashecho ${BASH_SOURCE[0]}我将上述脚本取名为 foo,将其置于我定义的一个专用于寄存脚本的目录内,并赋其可执行权限,而后执行 foo, $ foo/home/garfileo/.my-scripts/foo换一种形式执行 foo, $ bash /home/garfileo/.my-scripts/foo/home/garfileo/.my-scripts/foo再换一种形式, $ bash $(foo)/home/garfileo/.my-scripts/foo再换一种形式执行 foo, $ source $(foo)/home/garfileo/.my-scripts/foo在 Bash 的语法里,$(...) 称为命令替换,即开拓一个子 Shell,在其中执行括号内的命令,并以文本的模式返回后果。 上述试验揭示的是,foo 在运行时,能够确定本人身处何处。foo 能够,我也能够。 BASH_SOURCE[0] 与 $0 有什么区别?我想了起来,仿佛通过 $0 也能令一个脚本获知本身所处地位。将 foo 改为 #!/bin/bashecho ${BASH_SOURCE[0]}从新做一遍试验: $ foo/home/garfileo/.my-scripts/foo$ bash $(foo)/home/garfileo/.my-scripts/foo$ source $(foo)bash仅仅是在应用 source 执行 foo 时,失去的后果不是 foo 脚本的地位,而是 bash。 ...

March 11, 2021 · 2 min · jiezi

关于bash:Gar

Gar 是一个 Bash 脚本程序,用于治理 Markdown 文档我的项目,可将 Markdown 文档汇合其转化为 HTML 文档汇合。Gar 的运行,依赖 pandoc,git,tree 以及一个能在 Shell(命令行)里关上指定网页文件的网页浏览器。Gar 默认将 Firefox 作为网页浏览器,然而可在文档我的项目根目录的 gar.conf 文件中指定其它符合要求的网页浏览器。 文档我的项目初始化命令:gar init 文档我的项目名 例如: $ gar init demo[master (root-commit) 6f7dd1c] init 1 file changed, 2 insertions(+) create mode 100644 gar.conf以下命令可察看 gar init 发明了什么: $ cd demo$ ls -a .. gar.conf .git output source 图片$ gar treedemo├── gar.conf├── output├── source└── 图片$ git logcommit 6f7dd1c23c0cc8b18eb84b6a5236605eebd2bfbf (HEAD -> master)Author: xxx <xxx@yyy.zzz>Date: Tue Mar 9 07:30:53 2021 +0800 init文档我的项目初始化后,文档的撰写和编辑工作次要在 source 目录进行。Gar 将 Markdown 文档转化为 HTML 文档后,放在 output 子目录内。 ...

March 9, 2021 · 6 min · jiezi

关于bash:屏幕录制

在「用 Bash 脚本写一个截屏工具」一文的后记里,我将截屏脚本略加改变,失去了一个可录制屏幕中指定窗口区域的脚本。翻手为云,覆手为雨,全拜 ffmpeg 所赐。 我毫无新意地将这个录制屏幕的脚本取名为 recorder,内容为: #!/bin/bashNAME=$(date +"%Y-%m-%d %T" | sed -e "s/ /-/g; s/:/-/g")RECORD=/tmp/${NAME}.mkvOUTPUT=/tmp/output-${NAME}.mkv# 获取屏幕分辨率SCREEN=$(xrandr | grep -o "current [0-9]* x [0-9]*" | sed -e 's/current *//g')SCREEN_W=$(echo $SCREEN | sed -e 's/ x [0-9]*//')SCREEN_H=$(echo $SCREEN | sed -e 's/[0-9]* x //')# 获取窗口几何参数declare -a WIN_PARAMSWIN_PARAMS=($(xwininfo | sed -n -e '/^[[:space:]]*Absolute ..*[XY]/p; /^[[:space:]]*Relative ..*[XY]/p; /^[[:space:]]*Width:/p; /^[[:space:]]*Height:/p' | awk 'BEGIN{FS=":"}{print $2}'))# 结构现实中的截图区。# 之所以如此,与 xwininfo 输入的窗口左上角绝对坐标无关。MARGIN=${WIN_PARAMS[2]}WIN_X=$((${WIN_PARAMS[0]} - ${WIN_PARAMS[2]}))WIN_Y=$((${WIN_PARAMS[1]} - ${WIN_PARAMS[3]}))WIN_W=$((${WIN_PARAMS[4]} + ${WIN_PARAMS[2]} + $MARGIN))WIN_H=$((${WIN_PARAMS[5]} + ${WIN_PARAMS[3]} + $MARGIN))# 截图区越界解决if (($WIN_X < 0)); then WIN_X=0; fiif (($WIN_Y < 0)); then WIN_Y=0; fiif (($WIN_W + $WIN_X > $SCREEN_W)); then WIN_W=$(($SCREEN_W - $WIN_X)); fiif (($WIN_H + $WIN_Y > $SCREEN_H)); then WIN_H=$(($SCREEN_H - $WIN_Y)); fi# 录制指定窗口区域ffmpeg -video_size ${WIN_W}x${WIN_H} \ -framerate 30 -f x11grab \ -i :0.0+${WIN_X},${WIN_Y} \ -c:v libx264rgb -crf 0 -preset ultrafast $RECORD# 视频后处理ffmpeg -i $RECORD -c:v libx264rgb -crf 0 -preset veryslow $OUTPUT而后有些可惜,感觉没法像截屏脚本那样,能够绑定到桌面环境的某个快捷键上。起因是,ffmpeg 在录制屏幕时,须要我在其运行的命令行窗口里摁一下 q 键方能完结屏幕录制。过后感觉,无解。截屏脚本在抓到屏幕画面后会主动退出,所以不存在这样的问题。 ...

February 22, 2021 · 1 min · jiezi

关于bash:用-Bash-脚本写一个截屏工具

太极拳能不能打?学会了少林七十二绝艺,就能打,否则……不能打。拳理与编程,是相通的。白俄女芭蕾舞者的肌肉运用之妙,也是与拳理相通的。 在 Bash 看来,或者在任意一种在 Linux 环境里称得上 Shell 的物种看来,只有有了 ffmpeg、grep、sed、awk 以及一个 X 窗口零碎之类的货色,就能够用不到 50 行代码写出一个不错的截屏工具。当然,假使还有 GIMP 或相似的货色,风味更盛。 工夫的名义晓得上面这条命令,在我敲了回车键之后,会输入什么吗? $ date +"%Y-%m-%d %T"会输入 2021-02-19 23:32:18若以这样的后果作为截屏所得图像的文件名,是不是很好?反正我是打算这样做,先将工夫里的 : 变成短横: $ date +"%Y-%m-%d %T" | sed -e "s/ /-/g; s/:/-/g"工夫在流逝: 2021-02-19-23-34-47将上述代码整合起来,利用子 Shell,就有了截屏脚本 screenshot 的第一步……师出有名: #!/bin/bashNAME=$(date +"%Y-%m-%d %T" | sed -e "s/ /-/g; s/:/-/g")IMAGE=/tmp/${NAME}.pngecho $IMAGE为 screenshot 增加可执行权限: $ chmod +x screenshot而后将其放到零碎 PATH 变量所指定的目录内,执行这个脚本,就能够失去截屏后果的文件名: $ screenshot/tmp/2021-02-19-23-40-11.png工夫在流逝…… 世界有多大?世界有多大呢……单就截屏而言,世界就是计算机屏幕分辨率那么大。 X 窗口零碎有个工具叫 xrandr,它会通知我世界有多大: $ xrandrScreen 0: minimum 8 x 8, current 1600 x 900, maximum 32767 x 32767LVDS1 connected primary 1600x900+0+0 (normal left inverted right x axis y axis) 310mm x 170mm 1600x900 60.01*+ 59.82 40.00 1400x900 59.96 59.88 1368x768 60.00 59.88 59.85 1280x800 59.81 59.91 1280x720 59.86 60.00 59.74 1024x768 60.00 1024x576 60.00 59.90 59.82 960x540 60.00 59.63 59.82 800x600 60.32 56.25 864x486 60.00 59.92 59.57 800x450 60.00 640x480 59.94 720x405 59.51 60.00 58.99 640x360 59.84 59.32 60.00 VGA1 disconnected (normal left inverted right x axis y axis)VIRTUAL1 disconnected (normal left inverted right x axis y axis)然而,我感觉它的废话太多了。它所说的,只有第一句是我想晓得的: ...

February 20, 2021 · 3 min · jiezi

关于bash:Bash-常用命令记录

1. 递归查找某目录下有具体后缀的文件,并cp到指定目录find $SEARCHING_DIR -name "*.wav" -exec cp {} $TAR_DIR \;若只查找文件,前面可加上-type f 2. 查看某个文件行数wc -l $TAR_DIR 3. 查看目以后录下的文件数量(蕴含子目录的文件)ls -lR|grep "_"|wc -l 4. 查看当前目录下文件夹的数量(不蕴含子目录的文件夹)ls -l|grep "d"|wc -l蕴含与否取决于 ls后加不加-R参数,文件夹还是文件取决于grep后的”d“与否。 5. 查看当前目录下以test结尾的文件的数量(蕴含子目录中的文件)ls -lR test*|grep "_"|wc -l 6. 查看当前目录下各个文件夹所占物理空间du -sh * 7. 查看以后已挂载磁盘占用空间df -lh 继续更新~

December 14, 2020 · 1 min · jiezi

如何写一个命令行的秒表

序言相信各位读者对秒表都不陌生,智能手机上通常都有这样一款软件 有一天心血来潮,便想要“复刻”一个命令行版本的秒表程序——主要是想尝试一下新学会的、“原地更新”的技能,而不是一行接一行地输出。程序的运行效果如下 那么这是怎么做的呢? 实现思路及代码如何获取流逝的时间长度?要实现一个秒表,首先要知道从开始计时至今过了多久。在*nix系统中,表示时刻的事实标准是Epoch Time,在shell脚本中要获取Epoch Time可以用date命令。再用首尾时刻相减便得到了期间流逝的秒数了,示例代码如下 begin_at=$(date '+%s')# 睡个觉end_at=$(date '+%s')((interval=${end_at} - ${begin_at}))双圆括号是一种在shell脚本中执行算术运算的语法,其它语法可以参见Math in Shell Scripts。 如何换算为时分秒?有了interval中存储的总秒数后,换算成时分秒便是轻而易举的事情,示例代码如下 ((hours=${interval} / 3600))((minutes=(${interval} % 3600) / 60))((seconds=(${interval} % 3600) % 60))如何输出形如hh:mm:ss的格式?hh:mm:ss的意思是分别用两个十进制数字显示时分秒,并以冒号分隔它们。如果有任何一个单位的数值小于10,便用字符0填充左侧的空白。按这个格式,凌晨1点2分3秒便会显示为01:02:03。 要在命令行中打印字符串,最容易想到的便是echo命令,只可惜它不能方便地实现填充字符0的需求。 强人所难也不是不行,示例代码如下 hours=1minutes=2seconds=3if [ "${hours}" -lt '10' ];then echo -n "0${hours}"else echo -n "${hours}"fiecho -n ':'if [ "${minutes}" -lt '10' ];then echo -n "0${minutes}"else echo -n "${minutes}"fiecho -n ':'if [ "${seconds}" -lt '10' ];then echo -n "0${seconds}"else echo -n "${seconds}"fi更优雅的方法是用printf命令来自动填充左侧的字符0 ...

July 3, 2020 · 1 min · jiezi