Shell:修订间差异

来自牛奶河Wiki
跳到导航 跳到搜索
→‎BASE
 
(未显示2个用户的17个中间版本)
第8行: 第8行:


====环境变量====
====环境变量====
. ~/.bash_profile
. ~/.bash_profile
source .bash_profile
# 上述一般在 bash 环境下会调用 .bashrc,默认有如下代码:
if [ "$BASH" ]; then
  if [ -f ~/.bashrc ]; then
    . ~/.bashrc
  fi
fi
 
====特殊变量====
echo [-ne][字符串]
-n 不输出最后的 \n
-e 启用反斜线转义
-E 不启用反斜线转义
{| class="wikitable"
!变量
!含义
|-
|$0
|当前脚本的文件名
|-
|$n
|传递给脚本或函数的参数。n 表示第几个参数
|-
|$#
|传递给脚本或函数的参数个数
|-
|$*
|传递给脚本或函数的所有参数
|-
|$@
|传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同
|-
|$?
|上个命令的退出状态,或函数的返回值,0=OK
|-
|$$
|当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程ID
|}
{| class="wikitable"
!$0
!含义
!
|-
|0
|成功
|
|-
|1
|一般性錯誤,命令失敗
|Operation not permitted
|-
|2
|命令参数或格式错误
|No such file or directory
|-
|126
|命令或脚本无执行权限
|Required key not available
|-
|127
|命令未找到
|Key has expired
|-
|130
|被用戶通过 Ctrl+C 終止(信号 2)
|Owner died
|-
|137
|被 SIGKILL 信号终止(信号 9)
|No more records (read after end of file)
|}


====转义====
====转义====
 
* <nowiki>''</nowiki> 单引号,硬转义,所有的shell元字符、通配符都会被关掉。注意,硬转义中不允许出现’(单引号)。
*<nowiki>''</nowiki> 单引号,硬转义,所有的shell元字符、通配符都会被关掉。注意,硬转义中不允许出现’(单引号)。
*“” 双引号,软转义,只允许出现特定的shell元字符($,`,\):$用于变量值替换、`用于命令替换、\用于转义单个字符
*“” 双引号,软转义,只允许出现特定的shell元字符($,`,\):$用于变量值替换、`用于命令替换、\用于转义单个字符
*\ 反斜杠,转义, 去除其后紧跟的元字符或通配符的特殊意义
*\ 反斜杠,转义, 去除其后紧跟的元字符或通配符的特殊意义
第21行: 第91行:


====与或非====
====与或非====
*与 && 或: -a
*与 && 或: -a
*或 || 或: -o
*或 || 或: -o
第27行: 第96行:


====根据结果分支====
====根据结果分支====
grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not supported"
grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not supported"


====输出====
====输出====
*错误(stderr)信息转为标准输出
*错误(stderr)信息转为标准输出
2>&1
2>&1
*标准输出(stdout)转为文件
* 标准输出(stdout)转为文件
1>/tmp/log.txt
1>/tmp/log.txt
 
====将字符串作为shell命令执行====
res=`eval "${CMD}"`
====将结果作为字符串赋值给变量====
res=$(echo $ABC)
REDIS_PASSWORD=$(kubectl get secret --namespace kube-nodelm redis -o jsonpath="{.data.redis-password}" | base64 -d)
====保持变量换行====
INFO=$(smem -U root) && echo "$INFO"
====排序保留第一行====
INFO=$(smem -U root) && echo "$INFO" | head -n 1 && echo "$INFO" | sed '1d' | sort -k7nr | head -n 10
 
====特殊字符====
PA=$(echo -ne '\001')


===代码===
===代码===
====Info ====
## m02(10.10.137.188)
HOST=`hostname`
IP=`ping $HOST -c1|xargs|awk -F')' '{print $1}'|awk -F'(' '{print $2}'`
- OR -
IP=`ifconfig | grep 'inet ' | grep -v 'inet 127.0.0.1 ' |awk '/broadcast|Bcast/' | awk '{print $2}'`
echo "$HOST($IP)"
# network
ETH=$(ls /sys/class/net | awk '/^e/{print}')
# IP
IPV4=$(curl ipv4.icanhazip.com)


====时间====
====时间 ====
  ## 2022/08/29 16:23:01
  ## 2022/08/29 16:23:01
  TIMEID=`date '+%Y/%m/%d %H:%M:%S'`
  TIMEID=`date '+%Y/%m/%d %H:%M:%S'`
第52行: 第145行:
  # date "+%Y-%m-%d %H:%M:%S `echo "abc"`"      # 比较常见的用法
  # date "+%Y-%m-%d %H:%M:%S `echo "abc"`"      # 比较常见的用法


====Info====
====命令行参数判断 ====
## m02(10.10.137.188)
HOST=`hostname`
IP=`ping $HOST -c1|xargs|awk -F')' '{print $1}'|awk -F'(' '{print $2}'`
- OR -
IP=`ifconfig | grep 'inet ' | grep -v 'inet 127.0.0.1 ' |awk '/broadcast|Bcast/' | awk '{print $2}'`
echo "$HOST($IP)"
 
====命令行参数判断====
  if (( $# >= 1 )); then
  if (( $# >= 1 )); then
     YM=$1
     YM=$1
第68行: 第153行:
  fi
  fi
  YY=`echo $YM |cut -c 1-4`
  YY=`echo $YM |cut -c 1-4`
====输入====
====输入 ====
  if [ "$1" == "" ];then
  if [ "$1" == "" ];then
     echo "Not Parameter"
     echo "Not Parameter"
第86行: 第171行:
     echo OK
     echo OK
  fi
  fi
====字符比较====
==== 字符比较====
  if [ "$HASH_FN" == "$HASH_FN_OLD" ];then
  if [ "$HASH_FN" == "$HASH_FN_OLD" ];then
     echo "${FN} & ${FN_OLD} Hash Some."
     echo "${FN} & ${FN_OLD} Hash Some."
第93行: 第178行:
  fi
  fi


==== current directory ====
====current directory====
  curdir=$( pwd )
  curdir=$( pwd )
   
   
第135行: 第220行:
     echo ${FN}
     echo ${FN}
  done
  done
====遍历当前目录下的文件====
==== 遍历当前目录下的文件====
  for FN in ${FILENAME}*
  for FN in ${FILENAME}*
  do
  do
第145行: 第230行:
  find /u01/* -maxdepth 0 -type f
  find /u01/* -maxdepth 0 -type f


==== 读变量列表 ====
====读变量列表====
  HN_L=(
将本地多个文件复制到多台远程机器上。FN(需同步的本地文件列表),TM(目标机器名称或IP)
   192.168.0.110-node01
  <small><nowiki># Copy files to remote machines
   192.168.0.120-node02
FN=(
   192.168.0.130-node03
   /home/hdfs/.bashrc
)
  /opt/tez/conf/tez-site.xml
  /opt/hadoop/etc/hadoop/tez-site.xml
for F in ${HN_L[*]};do
  /opt/hive/conf/hive-site.xml
  HN=`echo $F|cut -d '-' -f1`
)
  ND=`echo $F|cut -d '-' -f2`
 
  echo ${HN} ${ND}
TM=(
done
  hdfs01
   hdfs02
   hdfs03
)
 
# source(local) -> target(TM)
# OK --> Sucessed
#
for F in ${FN[*]};do
  for T in ${TM[*]};do
    echo -n "Copy ${F} to ${T} : "
    scp -pq ${F} ${T}:${F} >/dev/null 2>&1 && echo "OK" || echo "Failed"
  done
done</nowiki></small>
将上面脚本改变一下,FN 定义可以放在用户登录的环境中,然后执行同步命令 hdcp。
<small><nowiki>## /bin/zhdcp
## Copy files to remote machines
#!/bin/sh
if [ "${FN}o" == "o" ];then
  echo 'FN is NULL.'
  exit 1
fi
 
TM=(
  hdfs01
  hdfs02
  hdfs03
)
 
# source(local) -> target(TM)
# OK --> Sucessed
#
for F in ${FN[*]};do
  for T in ${TM[*]};do
    echo -n "Copy ${F} to ${T} : "
    scp -pq ${F} ${T}:${F} >/dev/null 2>&1 && echo "OK" || echo "Failed"
  done
done</nowiki></small>
因为 FN 变量无法直接在 shell 中使用,故定义 alias:
<small>alias hdcp='FN="${FN[@]}" zhdcp'</small>
FN=(A B C)相当于定义了一个数组,${FN[0]} 亦可以写作 $FN 的值是 A。${FN[@]} 表示整个数组。
 
====循环====
====循环====
  CS=2
  CS=2
第175行: 第301行:
  <nowiki>[[ $string =~ ^$sub.*$]]</nowiki>
  <nowiki>[[ $string =~ ^$sub.*$]]</nowiki>
  <nowiki>[[ $string =~ ^.*$sub$]]</nowiki>
  <nowiki>[[ $string =~ ^.*$sub$]]</nowiki>
====字符串 按分隔符取段 ====
====字符串 按分隔符取段====
  # a bc 1 --> a bc
  # a bc 1 --> a bc
  STR1=${STR1% *}--> a bc
  STR1=${STR1% *}--> a bc
第185行: 第311行:
  echo $STR1 |cut -d ' ' -f2
  echo $STR1 |cut -d ' ' -f2
  echo $STR1 |cut -c 1-4
  echo $STR1 |cut -c 1-4
====计算 ====
====计算====
  V1 = $(expr $1 - $2)        # 须有空格
  V1 = $(expr $1 - $2)        # 须有空格
  let V1=$1-$2                # 须无空格
  let V1=$1-$2                # 须无空格
第191行: 第317行:
  threads=$(expr `cat /proc/cpuinfo |grep processor|wc -l` - 10)
  threads=$(expr `cat /proc/cpuinfo |grep processor|wc -l` - 10)
  let c=`cat /proc/cpuinfo |grep processor|wc -l`-10
  let c=`cat /proc/cpuinfo |grep processor|wc -l`-10
====特殊字符 ====
====特殊字符====
  PA=$(echo -ne '\004')
  PA=$(echo -ne '\004')
====参数====
====参数====
第202行: 第328行:
  user    0m0.000s
  user    0m0.000s
  sys    0m0.002s
  sys    0m0.002s
====LOG Format ====
====LOG Format====
[[分类:Develop]]
[[分类:Develop]]
[[分类:Linux]]
[[分类:Linux]]
[[分类:Shell]]
[[分类:Shell]]

2024年12月26日 (四) 09:52的最新版本

Shell 是一个用 C 语言编写的程序,是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

Ken Thompson 的 sh 是第一种 Unix Shell。

语法

环境变量

. ~/.bash_profile
source .bash_profile
# 上述一般在 bash 环境下会调用 .bashrc,默认有如下代码:
if [ "$BASH" ]; then
  if [ -f ~/.bashrc ]; then
    . ~/.bashrc
  fi
fi

特殊变量

echo [-ne][字符串]
-n 不输出最后的 \n
-e 启用反斜线转义
-E 不启用反斜线转义
变量 含义
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 表示第几个参数
$# 传递给脚本或函数的参数个数
$* 传递给脚本或函数的所有参数
$@ 传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同
$? 上个命令的退出状态,或函数的返回值,0=OK
$$ 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程ID
$0 含义
0 成功
1 一般性錯誤,命令失敗 Operation not permitted
2 命令参数或格式错误 No such file or directory
126 命令或脚本无执行权限 Required key not available
127 命令未找到 Key has expired
130 被用戶通过 Ctrl+C 終止(信号 2) Owner died
137 被 SIGKILL 信号终止(信号 9) No more records (read after end of file)

转义

  • '' 单引号,硬转义,所有的shell元字符、通配符都会被关掉。注意,硬转义中不允许出现’(单引号)。
  • “” 双引号,软转义,只允许出现特定的shell元字符($,`,\):$用于变量值替换、`用于命令替换、\用于转义单个字符
  • \ 反斜杠,转义, 去除其后紧跟的元字符或通配符的特殊意义

  *在“”中不用使用转义,但再次使用时,变量应该加“”,如:

c="a * b"
echo "$c"

与或非

  • 与 && 或: -a
  • 或 || 或: -o
  • 非 !

根据结果分支

grep -q sse4_2 /proc/cpuinfo && echo "SSE 4.2 supported" || echo "SSE 4.2 not supported"

输出

  • 错误(stderr)信息转为标准输出
2>&1
  • 标准输出(stdout)转为文件
1>/tmp/log.txt

将字符串作为shell命令执行

res=`eval "${CMD}"`

将结果作为字符串赋值给变量

res=$(echo $ABC)
REDIS_PASSWORD=$(kubectl get secret --namespace kube-nodelm redis -o jsonpath="{.data.redis-password}" | base64 -d)

保持变量换行

INFO=$(smem -U root) && echo "$INFO"

排序保留第一行

INFO=$(smem -U root) && echo "$INFO" | head -n 1 && echo "$INFO" | sed '1d' | sort -k7nr | head -n 10

特殊字符

PA=$(echo -ne '\001')

代码

Info

## m02(10.10.137.188)
HOST=`hostname`
IP=`ping $HOST -c1|xargs|awk -F')' '{print $1}'|awk -F'(' '{print $2}'`
- OR -
IP=`ifconfig | grep 'inet ' | grep -v 'inet 127.0.0.1 ' |awk '/broadcast|Bcast/' | awk '{print $2}'`
echo "$HOST($IP)"
# network
ETH=$(ls /sys/class/net | awk '/^e/{print}')
# IP
IPV4=$(curl ipv4.icanhazip.com)

时间

## 2022/08/29 16:23:01
TIMEID=`date '+%Y/%m/%d %H:%M:%S'`
DATEID=`date +%Y%m%d`

DATEID=`date -dyesterday +%Y%m%d`
DATEID=`date -dtomorrow +%Y%m%d`
DATEID=`date -d "$date last month" +%Y%m%d`
DATEID=`date -d "$date next month" +%Y%m%d`

DATEID=`date -d "$date -1 day" +%Y%m%d`
DATEID=`date -d "$date -1 month" +%Y%m%d`

# date "+%Y-%m-%d %H:%M:%S `echo "abc"`"      # 比较常见的用法

命令行参数判断

if (( $# >= 1 )); then
    YM=$1
else
    echo $0 'YM=yyyymm'
    exit 1
fi
YY=`echo $YM |cut -c 1-4`

输入

if [ "$1" == "" ];then
    echo "Not Parameter"
fi
if [ "$1" == "" ]; then
    CS=1
#elif … ; then
else
    CS=$1
fi

数值比较

if ((${PS} > 0)); then
   echo "Task: $CMD exist."
   exit 1
else
   echo OK
fi

字符比较

if [ "$HASH_FN" == "$HASH_FN_OLD" ];then
    echo "${FN} & ${FN_OLD} Hash Some."
else
    echo "Backup ${HASH_FN} Finished."
fi

current directory

curdir=$( pwd )

curdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
BASH_SOURCE[0] 等价于 BASH_SOURCE, 取得当前执行的 shell 文件所在的路径及文件名。

上一级目录
predir="$(
   cd ..
   pwd
)"

file or path exist

## if file exist, run
[ -f /etc/profile ] && source /etc/profile
# if path not exist, create
[ ! -d $VPATH ] && mkdir -p $VPATH

-e filename 如果 filename存在,则为真
-d filename 如果 filename为目录,则为真
-f filename 如果 filename为常规文件,则为真
-L filename 如果 filename为符号链接,则为真
-r filename 如果 filename可读,则为真
-w filename 如果 filename可写,则为真
-x filename 如果 filename可执行,则为真
-s filename 如果文件长度不为0,则为真
-h filename 如果文件是软链接,则为真

按行读文件

while read LN
do
    echo ${LN}
done < ${LN_NAME}

cat ${LN_NAME} | while read LN
do
    echo $LN
done

for FN in ${LN_NAME}
do
    echo ${FN}
done

遍历当前目录下的文件

for FN in ${FILENAME}*
do
    echo ${FN}
done

遍历当前目录下的目录

find /u01/* -maxdepth 0 -type d
# 遍历当前目录下的文件
find /u01/* -maxdepth 0 -type f

读变量列表

将本地多个文件复制到多台远程机器上。FN(需同步的本地文件列表),TM(目标机器名称或IP)

# Copy files to remote machines
FN=(
  /home/hdfs/.bashrc
  /opt/tez/conf/tez-site.xml
  /opt/hadoop/etc/hadoop/tez-site.xml
  /opt/hive/conf/hive-site.xml
)

TM=(
  hdfs01
  hdfs02
  hdfs03
)

# source(local) -> target(TM)
# OK --> Sucessed
#
for F in ${FN[*]};do
  for T in ${TM[*]};do
    echo -n "Copy ${F} to ${T} : "
    scp -pq ${F} ${T}:${F} >/dev/null 2>&1 && echo "OK" || echo "Failed"
  done
done

将上面脚本改变一下,FN 定义可以放在用户登录的环境中,然后执行同步命令 hdcp。

## /bin/zhdcp
## Copy files to remote machines
#!/bin/sh
if [ "${FN}o" == "o" ];then
  echo 'FN is NULL.'
  exit 1
fi

TM=(
  hdfs01
  hdfs02
  hdfs03
)

# source(local) -> target(TM)
# OK --> Sucessed
#
for F in ${FN[*]};do
  for T in ${TM[*]};do
    echo -n "Copy ${F} to ${T} : "
    scp -pq ${F} ${T}:${F} >/dev/null 2>&1 && echo "OK" || echo "Failed"
  done
done

因为 FN 变量无法直接在 shell 中使用,故定义 alias:

alias hdcp='FN="${FN[@]}" zhdcp'

FN=(A B C)相当于定义了一个数组,${FN[0]} 亦可以写作 $FN 的值是 A。${FN[@]} 表示整个数组。

循环

CS=2
for (( i=1; i<=${CS}; i++ ))
do
   echo $i
done

字符串 子串

# 包含
[[ $string =~ $sub]]
# 开头
[[ $string = $sub*]]
# 结束
[[ $string = *$sub]]

# 正则
[[ $string =~ ^.*$sub.*$]]
[[ $string =~ ^$sub.*$]]
[[ $string =~ ^.*$sub$]]

字符串 按分隔符取段

# a bc 1 --> a bc
STR1=${STR1% *}--> a bc
STR1=${STR1%% *}  --> a
#  a bc 1 --> bc 1
STR1=${STR1#* }
STR1=${STR1##* } --> 1
# cut
echo $STR1 |cut -d ' ' -f2
echo $STR1 |cut -c 1-4

计算

V1 = $(expr $1 - $2)         # 须有空格
let V1=$1-$2                 # 须无空格

计算主机线程数-10

threads=$(expr `cat /proc/cpuinfo |grep processor|wc -l` - 10)
let c=`cat /proc/cpuinfo |grep processor|wc -l`-10

特殊字符

PA=$(echo -ne '\004')

参数

管道

read VAR1                    # 可从标准输入或管道接收

sleep

time sleep 0.030

real    0m0.032s
user    0m0.000s
sys     0m0.002s

LOG Format