Shell:基础入门

说明 时间
首次发布 2019年08月18日
最近更新 2020年07月01日

写在最前:此为笔者系统学习shell的笔记,初衷是方便自己查阅和复习。囿于笔者属于入门级别,难免有理解不对的地方,望留言指正。

插入说明: 由于Mac自带的sed是基于BSD的,远没有Linux下的强大,可以安装gnu-sed。具体操作如下:

  • 1、安装 最新Xcode 并执行下面脚本:

    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    
  • 2、将下面的命令行添加到 ~/.bashrc~/.zshrc里:

    export PATH="$(brew --prefix coreutils)/libexec/gnubin:/usr/local/bin:$PATH"
    
  • 3、安装GNU命令行工具:

    brew install coreutils
    
  • 4、安装 gnu-sed:

    brew install gnu-sed
    
  • 5、之后按照提示,将 export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH" 也添加到 ~/.bashrc~/.zshrc就可以了。

    测试是否成功安装:

    sed --version
    
    # 输出
    https://www.topbug.net/blog/2013/04/14/install-and-use-gnu-command-line-tools-in-mac-os-x/sed --version
    sed (GNU sed) 4.8
    Copyright (C) 2020 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    Written by Jay Fenlason, Tom Lord, Ken Pizzini,
    Paolo Bonzini, Jim Meyering, and Assaf Gordon.
    
    This sed program was built without SELinux support.
    
    GNU sed home page: <https://www.gnu.org/software/sed/>.
    General help using GNU software: <https://www.gnu.org/gethelp/>.
    E-mail bug reports to: <bug-sed@gnu.org>.
    

    参考: Mac安装Linux sed


一、升级bash

由于macOS自带bash版本为3.x,不支持 关联数组(bash V4.0+)等,那么需要先升级bash。

    1. 查看当前版本
    bash --version
    
    1. Homebrew安装最新bash
    brew install bash
    
    1. 打开 /etc/shells 文档,将 /usr/local/bin/bash 添加进去。
    # List of acceptable shells for chpass(1).
    # Ftpd will not allow users to connect who are not using
    # one of these shells.
    
    /bin/bash
    /bin/csh
    /bin/dash
    /bin/ksh
    /bin/sh
    /bin/tcsh
    /bin/zsh
    #新添加的
    /usr/local/bin/bash
    
    1. 设置默认Shell
    chsh -s /usr/local/bin/bash
    
    如果想修改root用户,执行以下操作:
    sudo chsh -s /usr/local/bin/bash
    
    注意:以上操作完之后,需要重启终端才能生效。
    1. 使用新版本Bash时,需要在shebang中明确指定新版本/usr/local/bin/bash
    #!/usr/local/bin/bash
    echo $BASH_VERSION
    
二、shell特点
  • 1、快捷键
组合键 功能
Ctrl+A 光标移动到命令最前面
Ctrl+E 光标移动到命令最后面
Ctrl+L 清屏
Ctrl+K 清除光标之后的内容
Ctrl+U 清除本次输入的所有内容
  • 2、前后台作业控制
项目 功能
Ctrl+C 结束进程
Ctrl+|强制结束进程
Ctrl+Z 将当前进程切换到后台
jobs 查看所有的进程
  • 3、输入输出重定向
项目 功能
0 文件描述符,表示标准输入(stdin)
1 文件描述符,表示标准输出(stdout)
2 文件描述符,表示标准错误(stderr)
> 默认为标准输出重定向,与 1> 相同
>> 追加输出
&>file 把 标准输出 和 标准错误输出 都重定向到文件file中
1>&2 正确返回值传递给2输出通道,&2表示2输出通道
2>&1 错误返回值传递给1输出通道,同样&1表示1输出通道
cat < /etc/hosts 将hosts的内容输入到cat
cat < /etc/hosts > HOST.txt 将hosts的内容输入到cat,之后定向到HOST.txt,而不输出到屏幕
cat <<EOF 多行输入(<<delimiter符号成为“此处文档”,delimite称为分界符)
cat > file.txt <<-EOF 多行输入,并把文本保存到file.txt(-用于删除输入文本行所有开头的Tab键,但开头的空格不会被删除)
  • 4、运算符

    • a. | 管道符号,是unix一个很强大的功能,符号为一条竖线:"|"。
      格式:

      command 1 | command 2
      

      他的功能是把第一个命令command 1执行的结果作为command2的输入传给command 2。
      如:

      ls -s | sort -n
      
    • b. && 运算符:
      格式

      command1  && command2
      

      &&左边的命令(命令1)返回真(即返回0,成功被执行)后,&&右边的命令(命令2)才能够被执行;换句话说,“如果这个命令执行成功&&那么执行这个命令”。

    • c.|| 运算符:
      格式

      command1 || command2
      

      ||则与&&相反。如果||左边的命令(command1)未执行成功,那么就执行||右边的命令(command2);或者换句话说,“如果这个命令执行失败了||那么就执行这个命令。

    • d.() 运算符:
      如果希望把几个命令合在一起执行,shell提供了两种方法。既可以在当前shell也可以在子shell中执行一组命令。
      格式:

      (command1;command2;command3....)               多个命令之间用;分隔
      

      说明:

        1. 一条命令需要独占一个物理行,如果需要将多条命令放在同一行,命令之间使用命令分隔符(;)分隔。执行的效果等同于多个独立的命令单独执行的效果。
        1. () 表示在当前 shell 中将多个命令作为一个整体执行。需要注意的是,使用 () 括起来的命令在执行前面都不会切换当前工作目录,也就是说命令组合都是在当前工作目录下被执行的,尽管命令中有切换目录的命令。
        1. 命令组合常和命令执行控制结合起来使用。
  • 5、通配符
    *(匹配任意多个字符)、?(匹配任意一个字符)、[](匹配中括号里的任意一个字符)、\(用作转义)和正则表达式的含义一致。
    ()表示在子shell中执行;
    {}表示集合,如touch file{1..9}

  • 6、检查和调试
    查看脚本语法是否有错误:

    bash -n scriptName.sh
    

    跟踪执行:

    sh -vx scriptName.sh
    

二、常用命令
  • 1、tee
    [-a] 追加;[-i ] 忽略SIGINT信号。
    tee1>比较相似,最大不同 > 重定向只会将内容重定向到文件,而不会在终端输出;而 tee 命令会将内容重定向到文件的同时,在终端输出。

  • 2、grep 选项一览

    • grep 选项一览
  • 3、基于gnu-sed的sed
    • sed命令选项
    • sed定位文本方法
    • sed编辑命令
  • 4、awk
    • a. BEGIN 和 END 分别在action之前和之后执行。
    cat IFS.json | awk 'BEGIN {FS=","} { print substr($0,0,100) } END { print length("ok")}'
    
    • b. 注意: 在 awk 里调用Linux命令时,需要用双引号将这些命令引起来,如下面的 sort。(解释下面的命令:awk命令现将域分隔符指定为冒号,然后打印第1域,将打印结果通过管道传输给sort命令,sort命令对第1域进行排序,然后输出,结果将/etc/passwd的第1域按字母排序后打印。)
    awk -F ':' '{print $1 | "sort"}' /etc/passwd
    
    awk 'BEGIN {while (("ls /usr" | getline d) > 0) print d}'
    
  • 5、sort选项

    • sort选项
  • 6、printf选项

    • 图片.png
  • 7、uniq选项

    • uniq选项
  • 8、find选项

    • find选项
  • 9、cut选项

    • cut选项
  • 10、paste选项

    • paste选项
  • 11、数组

array=(11 22 [5]=55  66 77)
echo "个数: ${#array[@]}"

# 表示数组的所有元素,在不用""引起来的情况下是一样的
# 如下所示,双引号引起来的时候,就稍微有点不同:
  # @:会使打印换行;
  # *:则会在同一行里打印
for ele in "${array[@]}"; do
    echo "遍历的元素: $ele"
done
  • 12、tr选项:tr相当于简化版的sed,tr能做的sed都能做。
    • tr选项
# 如:
tr -d "\n" <tj.json
tr -s "\n" <tj.json
  • 13、tar选项
    • tar选项
# 如:
tar -xvf # 解压非gzip格式的压缩包
tar -zxvf # 解压gzip格式的压缩包
tar -cf 压缩包名 需要处理的文件 # 实际上是将多个文件放在一起,并没有压缩
tar -cf 压缩包名 # 列出包内容
tar -uf 压缩包名 需要更新的文件
tar -rf 压缩包名 需要添加的文件
  • 14、expr命令
    • 图片.png
  • 15、exec命令: 可以通过文件标识符打开或关闭文件,也可将文件重定向到标准输入 或 将标准输出重定向到文件。
    • 高级I/O重定向符号及意义
    • a. 标准输入重定向到文件

# FD 8是 FD 0的副本,用于恢复FD 0
exec 8<&0
# 将标准输入重定向到 newFile
exec < newFile
# 多去newFile的第一行和第二行,并打印
read a
read b
echo $a
echo $b

# 0<&8:将FD 8复制到FD 0,FD 8是原来的标准输入,FD 0从FD 8恢复原状
# 8<&-:关闭FD 8,其他进程可以重复使用FD 8
exec 0<&8 8<&-

# 在执行read命令时,read命令从键盘输入读取数据
read c
echo $c # 标准输入恢复为键盘输入
  • b. 标准输出重定向到文件
# FD 8为标准输出的副本,用于恢复FD 1
exec 8>&1
# 将标准输出重定向到log.json
exec > log.json

# 测试输出是否写入log.json
echo "Say you love me"
date
echo "OK, you win"

# 1>&8:将FD 8复制到FD 1,FD 8是原来的标准输出,FD 1从FD 8恢复原状
# 8>&-:关闭FD 8,其他进程可以重复使用FD 8
exec 1>&8 8>&-

# 测试标准输出是否恢复原状
echo "OK, you win"
  • c. 证明 &>file 是将标准输出 和 标准错误输出重定向到文件。
#!/bin/bash

# 将标准输出复制到FD 8,将标准错误输出复制到FD 9
exec 8>&1 9>&2

# 重定向到文件err.json
exec &> err.json

# 执行命令生成一个错误输出
ls noExistFile

# 生成一个标准输出
date

# 恢复标准输出和标准错误输出,并关闭FD 8和FD 9
exec 1>&8 2>&9 8>&- 9>&-

# 再次执行命令生成标准输出 和 标准错误输出,检验是否恢复了原状
# 执行命令生成一个错误输出
ls noExistFile

# 生成一个标准输出
date
  • 16、/dev/null 说明:是一个控设备文件,送到其中的所有数据都会被丢弃,常用方式如下:
# aaa 为不存在的文件
cat aaa >/dev/null 2>&1ls foo >/dev/null 2>&1
  • 17、代码块重定向: 适用于 while、until、for 等循环结构,也可以是 if/then 测试结构,或者是函数。
#!/bin/bash

ls /etc > log.log

while [[ "$filename" != "rpc" ]]; do
    read filename
    let "count+=1"
done < log.log

echo "非rc.d的文件有${count}个"
read -p "请输入一个值:" test
echo $test
  • 18、命令行处理流程

  • 命令行处理流程1
  • 命令行处理流程2
  • 19、eval命令: eval命令将其参数作为命令行,让Shell重新执行该命令行。eval在处理简单命令时,与直接执行该命令没有区别。但在处理复杂内容时,就能显示出来。总结成一句话:如果变量中包含任何需要Shell直接在命令中看到的字符,就需要用eval命令。如:命令结束符(;、|、&)、I/O重定向符(<、>)和引号等对Shell具有特殊意义的符号,必须直接出现在命令行中。

a="|"
evaeval ls $a wc -l
  • 20、Shell执行命令的过程

    • Shell执行命令的过程
  • 21、Ctrl组合键、信号类型及其意义

    • Ctrl组合键、信号类型及其意义
  • 22、颜色编码和含义
    格式:

echo -e "\033[44;37;5m Hello \033[0m"
  • 颜色编码和含义

小例子
# #!表示告诉系统后面的参数是执行文件的程序
#!/bin/sh

# 简单的打印
# echo 'hello'

# 条件语句
# if [[ 5 > 6 ]]; then
#   echo '5 > 6'
# elif [[ 3 < 4 ]]; then
#   echo '3 < 4'
# fi


# 打印当前工作路径
# path=`pwd`
# if [[ -f "$path" ]]; then
#   echo '上是一个文件'
# elif [[ -f "$path/hello.sh" ]]; then
#   echo '下是一个文件'
# fi


# && 和 || 的使用:
# &&表示前面的条件成立,执行后面的操作
# ||表示前面的条件不成立,则执行后面的操作
# path=`pwd`
# # [ -f "$path/hello.sh" ] && echo 'Everythings OK'
# # [ -w "$path/各个文件占用空间.txt" ] || { echo '不可写'; exit 1; }


# 拷贝等操作
# filename="sum.txt"
# echo $filename
# cp 各个文件占用空间.txt $filename
# # head $filename


# 筛选
# grep "SDK" $filename | wc -l 



# 类似于switch
# echo "What's your favourite OS? Please input number"
# select OS in "Linux" "Windows" "MacOS" "Ohter"; do
#   break
# done
# echo "You have choosed $OS"



# echo "*.txt"
# echo $SHELL



# 测试根据输入,判断文件类型
# ftype=`file "$1"`
# echo $ftype



# ftype=`file "$1"`
# case "$ftype" in
# "$1: Zip archive"*)
#   unzip "$1" ;;
# "$1: gzip compressed"*)
#   gunzip "$1" ;;
# "$1: bzip2 compressed"*)
#   bunzip2 "$1" ;;
# *) error "File $1 can not be uncompressed with smartzip";;
# esac



# 相当于switch
# flength=$1
# len=${#flength}
# case $len in
#   "0" )
#       echo "=0";;
#   "1" )
#       echo "=1";;
#   "2" )
#       echo "=2";;
#   * )
#       echo "大于2";;
# esac


# switch2
# select var in A B C; do
#   echo 'var is $var'
#   break
# done


# 遍历
# for item in $*; do
#   echo $item
# done


# 反斜杠'\'转义
# >> 代表追加写入
# > 覆盖写入
# echo \*.txt >> my.txt
# echo \*.txt >> my.txt
# echo \*.txt >> my.txt


# `$#`表示参数的个数
# echo $#


# shift:每执行一次,变量的个数($#)减一,而变量值提前一位
# until [[ $# -eq 0 ]]; do
#   echo "第一个参数为: $1 参数个数为: $#"
#   shift
# done
# 该例子输入:1 2 3 4 5
# 输出:
# 第一个参数为: 1 参数个数为: 5
# 第一个参数为: 2 参数个数为: 4
# 第一个参数为: 3 参数个数为: 3
# 第一个参数为: 4 参数个数为: 2
# 第一个参数为: 5 参数个数为: 1



# 添加帮助(Here Docoments)
# 语法结构如下
# cat <<HELP 
# 文本内容 
# HELP 
# 任何出现在两个HELP之间的文本内容,但请注意如果出现'$var'的内容会被替换,除非是'$'用'\' 转义了。

# help() {
# cat << HELP
# 输入的参数个数必须要大于3个
# HELP
# exit 0
# }

# # 条件判断的,要注意条件与`[` 和 `]`之间有空格
# [ $# -gt 3 ] || help  #如果参数个数小于3,就会执行help
# [ "$1" = "-h" ] && help   #如果输入的是`-h`,也要输出help

# index=0
# for item in $*; do
#   echo "当前的索引: $index, 值: $item"
#   # 参数index自加的四种方法,注意index有没有`$`
#   # index=`expr $index + 1`
#   # let index++
#   # ((index++))
#   # let index+=1
# done



# 数组
# array=(11 22 33 44)
# echo ${array[*]} #打印数组的元素
# 打印数组的长度
# echo ${#array[*]}
# echo ${#array[@]}

# echo ${array[@]:1:2}
# echo ${array[@]/2/a}
# echo ${array[@]}



# for循环打印下面这句话中不大于6的单词
# arr=(I am oldboy teacher welcome to oldboy training class)
# for (( i=0; i<${#arr[@]}; i++ )); do
#   length=`echo ${arr[i]} | wc -m`
#   if [ $length -le 6 ]; then
#       echo "${arr[i]}"
#   fi
# done

# 打印当前目录的父目录(需要修改)
# echo `basename $1`


# [-d /Lynn ] || mkdir -p /Lynn
[ -d /Lynn ] || mkdir -p /Lynn
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,724评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,104评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,142评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,086评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,076评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,914评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,220评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,871评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,318评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,834评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,951评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,574评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,162评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,162评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,383评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,349评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,652评论 2 343