shell学习


title: shell
date: 2020-09-08 15:07:04
categories:

  • [学习, shell]
    tags:
  • shell

介绍

{% note info %}
Shell 教程,主要基于bash基本等同于sh
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。
本文基本上是个简要教程,复杂的请参阅网上教程。
<span style="color:red;">简单手册</span> <span style="color:red;">Shell脚本编程30分钟入门</span>
{% endnote %}

基本使用

#!/bin/bash        指定脚本解释器,这里是用/bin/bash做解释器的
echo "hello world of shell"  # 打印文本

语法简介

变量

# 单行注释
:<<EOF
这是多行注释
可以多行
不过我看采用的人不多
EOF
myvar="test"                                             # 定义变量
readonly myvar                                           # 设置变量可读
echo "myvar is ${myvar}"                                 # 打印变量
unset myvar                                              # unset 命令不能删除只读变量。
echo "myvar is ${myvar}"                                 # 打印变量,变量还和原来一样
your_name='cxl'                                          # 单引号原样
str="Hello, I know you are \"$your_name\"! \n"           # 双引号里面允许变量,可以转义
echo -e $str                                             # 打印变量,-e 启用反斜杠转义的解释
echo 'hello'${your_name}' !'                             # 变量可以加大括号确认范围
echo ${#your_name}                                       # 打印字符串长度
echo ${your_name:1:2}                                    # 截取部分字符串
arr=(1 2 3 4 5)                                          # 数组声明
echo ${arr[0]}                                           # 根据下标打印数组
echo ${arr[@]}                                           # @符号打印所有数组元素
length=${#arr[@]}                                        # 取得数组长度
echo ${length}                                           # 打印数组长度
for ((i=0;i<$length;i++)); do                            # 遍历打印数组        
    echo "数组$i值:${arr[$i]}"
done
for var in ${arr[@]}; do                                 # 遍历数组
    echo "数组值:$var"
done

传递参数

#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

echo "Shell 传递参数实例!";
echo "参数总数:$#"
echo "当前进程id号:$$"
echo "所有参数,相当于多个字符串:$@"
echo "所有参数,相当于一个字符串:$*"
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
# 和$@相同,但"$*" 和 "$@"(加引号)并不同,"$*"将所有的参数解释成一个字符串,而"$@"是一个参数数组

./helloshell.sh 1 2 3
Shell 传递参数实例!
参数总数:3
当前进程id号:1633
所有参数,相当于多个字符串:1 2 3
所有参数,相当于一个字符串:1 2 3
执行的文件名:./helloshell.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3

# getopts
#!/bin/bash
while getopts "a:bc" arg #选项后面的冒号表示该选项需要参数
do
        case $arg in
             a)
                echo "a's arg:$optarg" #参数存在$optarg中

             b)
                echo "b"

             c)
                echo "c"

             ?)  #当有不认识的选项的时候arg为?
            echo "unkonw argument"
        exit 1

        esac
done

# getopt

要点:
1. getopt 用法
语法:getopt [options] [--] optstring parameters
例如:getopt ab:cd -a -b he free cat
输出:-a -b he -- free cat
            getopt 根据 ab:cd 将选项和参数 -a -b he free cat  解析为如下格式:
            -a -b he -- free cat
             其中 -- 将选项与非选项参数分开 free 和 cat 就时非选项参数
2. set --
-- Do not change any of the flags; useful in setting $1 to -.
set --  主要是影响特殊变量$1 $2 等,其实在上面的脚本中就是将$1 $2 等参数变量重新组合
例如:
set -- a b c
shell中的特殊位置变量$1 为a $2 为 b $3 为 c
3.如上脚本为build.sh 用法如下:
./build.sh -a -c -d -e dog
./build.sh -acde  dog
上面两个命令执行结果相同。

运算符


val=`expr 2 + 2`                    # 2+2不对中间必须有空格,写成2 + 2
echo "2+2=$val"
val=`expr 2 / 2`
echo "2/2=$val"
val=`expr 2 - 2`
echo "2-2=$val"
val=`expr 2 \* 2`                   # 乘号*必须转义
echo "2*2=$val"
val=`expr 2 % 2`
echo "2%2=$val"

a=10
b=20

if [ $a == $b]; then
    echo "a 等于 b"
fi
if [ $a != $b]; then
    echo "a 不等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]; then
    echo "a 小于 100 且 b 大于 15,-a表示且,也可以使用&&"
fi
if [ $a -lt 15 -o $b -lt 15 ]; then
    echo "a 小于 15 或 b 小于 15,-o表示或,也可以使用||"
fi
if [ ! false ]; then
    echo "非运算为true"
fi

str="welcome to shell"
if [ "$str" = "welcome to shell" ]; then
    echo "=号测试成功,==号和=号在[]中表示判断(字符串比较)时是等价的,!=是测试字符串不等于"
fi
if [ -z "$str1" ]; then
    echo "str1字符串不存在,所以使用-z返回true,最好用双引号括起来"
fi
if [ -n "$str" ]; then
    echo "str字符串已存在,长度大于0,-n返回true,最好用双引号括起来"
fi
if [ "$str" ]; then
    echo "使用$来检查字符串是否为空,如果字符串里面有空格必须用双引号括起来"
fi

# 文件测试运算符
[ -b /dev/sda ] && echo "is Block Device Driver 块设备文件"
[ -c /dev/tty7 ] && echo "is Character Device Drive 字符设备文件"
[ -d /dev/ ] && echo "is directory 目录"
[ -f /etc/nginx/nginx.conf ] && echo "is file 文件"
[ -g /etc/passwd ] && echo "is SUID/SGID set group id"
[ -k /etc/passwd ] && echo "is Sticky Bit"
[ -p /etc/passwd ] && echo "is 有名管道"
[ -u /etc/passwd ] && echo "is SUID 位 set user id"
[ -r /etc/passwd ] && echo "is 可读"
[ -w /etc/passwd ] && echo "is 可写"
[ -x /etc/passwd ] && echo "is 可执行"
[ -s /etc/passwd ] && echo "is 不为空"
[ -e /etc/passwd ] && echo "is 文件或目录已存在"
[ -L /etc/passwd ] && echo "is 符号链接"
[ -S /etc/passwd ] && echo "is socket"

命令实例

#!/bin/sh
read name 
echo "$name It is a test"
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"
echo `date`
printf "Hello, Shell\n"
# %s %c %d %f都是格式替代符
# %-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
# %-4.2f 指格式化为小数,其中.2指保留2位小数。
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg  
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543 
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876  

printf "%s\n" abc def
# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
printf "%s and %d \n" 

result=$[a+b] # 注意等号两边不能有空格
echo "result 为: $result"

test 和 [] 等效
if test -e ./notFile -o -e ./bash
then
    echo "至少存在一个文件"
else
    echo "两个文件都不存在"
fi
if [ -e ./notFile -o -e ./bash ]
then
    echo "至少存在一个文件"
else
    echo "两个文件都不存在"
fi

a=10
b=20
if [ $a == $b ]
then
   echo "a 等于 b"
elif [ $a -gt $b ]
then
   echo "a 大于 b"
elif [ $a -lt $b ]
then
   echo "a 小于 b"
else
   echo "没有符合的条件"
fi

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"  #  let 命令,它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量
done

# 无限循环
while :
do
    command
done
while true
do
    command
done
for (( ; ; ))

a=0

until [ ! $a -lt 10 ]
do
   echo $a
   a=`expr $a + 1`
done

echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
    1)  echo '你选择了 1'
    ;;
    2)  echo '你选择了 2'
    ;;
    3)  echo '你选择了 3'
    ;;
    4)  echo '你选择了 4'
        break
    ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
    ;;
esac

while :
do
    echo -n "输入 1 到 5 之间的数字:"
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你输入的数字为 $aNum!"
        ;;
        *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
            continue  # 永远不会结束
            break     # 保留break跳出循环
        ;;
    esac
done

# 函数
function demoFun1(){
    echo "这是我的第一个 shell 函数!"
    return `expr 1 + 1`
}

demoFun1
echo $?

init(){ :; }  # 空函数

输入/输出重定向

wc -l << EOF
    欢迎来到
    菜鸟教程
    www.runoob.com
    dddddd
EOF

# 0 是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。
# 如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写
command > file 2>&1   # 替换
command >> file 2>&1  # 追加
command > /dev/null 2>&1  # 直接丢弃结果

文件包含


. filename   # 注意点号(.)和文件名中间有一空格
source filename

linux 命令

awk

  • 遍历文件相加
echo -e "1\n2\n3\n4" > test.txt
awk '{ sum += $1 }; END { print sum }' test.txt
10
  • 按:分割,打印所有用户名
awk -F: '{ print $1 }' /etc/passwd
  • 读取配置文件,并输出到变量里
echo -e "DB_PWD=123456\nDB_USER=root" > test.txt
cat test.txt |sed "s#//# #g" | sed "s/=/ /g" | awk  '{if(NF>1){printf("%s=\"%s\";",$1,$2)}}'
DB_PWD="123456";DB_USER="root";
eval $(cat test.txt |sed "s#//# #g" | sed "s/=/ /g" | awk  '{if(NF>1){printf("%s=\"%s\";",$1,$2)}}')
echo $DB_PWD
123456

  • 分析url
param=`echo "$redirectUrl" | awk -F '?' '{print $2}'`;
echo "$param" | awk -F '&' '{i=1;while(i<=NF){n=split($i,array,"=");if(array[1]=="code"){print array[2];break;};i++;}}'
  • 分析php配置文件,找出session节host配置项
awk -F '=>' '{if($0~/\047session\047/){find=1;fl=0;fr=0}if(find){if($0~/\[/){fl++;};if($0~/\]/){fr++;};if($1~/\047host\047/){print $2;exit 0;}if(fl==fr){exit 99}}}' ../application/config.php | awk -F '\047' '{print $2,exit 0}'
'127.0.0.1',

curl

  • 静默方式-s,-k不检查证书 -c 创建cookie文件
result=`curl -s -k -c cxl_cookie https://10.0.0.42:1066`
 echo $result
{"status":0,"info":"调用接口成功","data":"home"}
  • 通过使用 -v 和 -trace获取更多的链接信息
curl  -v  -k -c "" -d "" -H "" https://10.0.0.42:1066
  • 打印返回的header(-i)
curl  -i  -k -c "" -d "" -H "" https://10.0.0.42:1066

cut

  • 按字节剪切
echo "test" | cut --b 2-4
est
  • 按字符剪切
echo "test" | cut -c 2-4
est

  • 多个分段用逗号分开
echo "test test"|cut -b 3-5,8
st s
  • 从文件获取
echo -e "星期一\n星期二\n星期三" > test.txt
cut -b 1-3 test.txt
星
星
星
  • 中文
echo "星期四 星期三" | cut -c 1-3
星
  • 按特殊字符分割
echo "root:test:ok" | cut -d : -f 1
root
  • 综合应用
echo "root:test:ok" | cut -d : -f 3 | cut -c 1
o

sed

  • 替换字符
echo "this ReplaceWord success" | sed "s/ReplaceWord/is/"
this is success
  • 替换文件
echo "this ReplaceWord success" > test.txt
cat test.txt
sed -i "s/ReplaceWord/is/" test.txt
cat test.txt
  • 使用正则
echo "this 1234 success" | sed -r "s/[0-9]+/is/"
this is success
  • -g表示所有匹配的都执行
echo "this 1234 success 1234" | sed -r "s/[0-9]+/is/g"
this is success is

  • 按行号删除文件内容
sed -i '1,50000d' "$cxl_log_file" # 删除50000万行
sed -i '1d' a.txt删首行
sed -i '$d' b.txt删尾行
sed -i 's/[ ]*//g' c.txt删空格
sed -i '/^$/d' d.txt删空行
sed -i ‘/^[0-9]*$/d' a.txt删包含数字的行
sed -i ‘1,2d’a.txt删2行
sed -i ‘/love/d’ a.txt删包含string的行
  • 修改指定行内容
sed -r 's/( 'host' *)./1"test"/' ../application/config.php

tr

#  转换为大写
echo "hello world" | tr [:lower:] [:upper:]
# 删除空格、数字和-号
echo "hello-123-world  empty" | tr -d '[:blank:][:digit:]-'
# 删除除空格、数字和-号以外的字符,和上一例子正相反
echo "hello - 123-world  empty" | tr -d -c '[:blank:][:digit:]-'
# 去掉连续重复字符
echo "helloooo oooo    isssso ookk" | tr -s " os"
# 删除window文件造成^M字符
cat file | tr -s "\r" "\n" > new_file
cat file | tr -d "\r" > new_file

uname

# 打印全部
uname -a
Linux 1604developer 4.4.0-89-generic #112-Ubuntu SMP Mon Jul 31 19:38:41 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
# 打印kernel-name
uname -s
Linux
# 打印机器网络名
uname -n
1604developer
# 打印kernel-release
uname -r
4.4.0-89-generic
# 打印kernel-version
uname -v
#112-Ubuntu SMP Mon Jul 31 19:38:41 UTC 2017
# 打印机器硬件名称
uname -m
x86_64
# 打印处理器类型
uname -p
x86_64
# 打印硬件平台
uname -i
x86_64
# 打印操作系统
uname -o
GNU/Linux

mktemp

# 生成随机文件
mktemp ttXXXX.tmp
# 生成随机目录
mktemp -d tempXXXXXX

jq

jq不是标准命令,是用来解析json字符串的命令,使用apt install jq -y 来安装

# get value
echo '{"status":0,"info":"we are success","data":{"client":{"client_id":"123456","client_secret":"567890"}}}' | jq ".status"
0
echo '{"status":0,"info":"we are success","data":{"client":{"client_id":"123456","client_secret":"567890"}}}' | jq ".info" | sed 's/"//g'
we are success
echo '{"status":0,"info":"we are success","data":{"client":{"client_id":"123456","client_secret":"567890"}}}' | jq ".data.client.client_id" | sed 's/"//g'
123456
# filter data
echo '{"status":0,"info":"we are success","data":{"client":{"client_id":"123456","client_secret":"567890"}}}' | jq '.data|.client'
{
  "client_id": "123456",
  "client_secret": "567890"
}

xargs

# 当你尝试用rm 删除太多的文件,你可能得到一个错误信息:/bin/rm Argument list too long. 用xargs 去避免这个问题
find ~ -name '*.log' -print0 | xargs -0 rm -f
# 获得/etc/ 下所有*.conf 结尾的文件列表,有几种不同的方法能得到相同的结果,下面的例子仅仅是示范怎么实用xargs ,在这个例子中实用 xargs将find 命令的输出传递给ls -l
find /etc -name "*.conf" | xargs ls –l
# 假如你有一个文件包含了很多你希望下载的URL, 你能够使用xargs 下载所有链接
cat url-list.txt | xargs wget –c
# 查找所有的jpg 文件,并且压缩它
find / -name *.jpg -type f -print | xargs tar -cvzf images.tar.gz
# 拷贝所有的图片文件到一个外部的硬盘驱动
ls *.jpg | xargs -n1 -i cp {} /external-hard-drive/directory
# 查找另一个目录同名文件,-n1表示每行一个参数 -i表示用{}表示输出的每行记录
ls /home/cxl/git-svn/spi/spi-php/bin/res/supervisor | xargs -n1 -i echo {}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容