IC脚本—— Shell基本使用

IC 开发常常在 Linux 下进行,而 Linux 下最常用的就是 shell 脚本。Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。在之前的文章《Linux常用技巧》中已经介绍了一些 Linux 基本知识,掌握这些基本知识后就可以再稍微花点时间学一学 Shell 脚本。当然,这里的目标不是成为 Shell 脚本大师,只是期望懂得一些基础概念,可以在实际工作中看懂或开发一些简单脚本,以方便我们的工作。

声明:本篇文章大量摘抄了菜鸟网 Shell 教程以及其他网络文章,只是个人学习理解的笔记,没有任何营养价值,仅供参考。

1:Shell基础概念

1.1: Shell 不同版本

Shell 种类众多,常见的有 sh、bash、csh等。

  • sh:全称是 Bourne shell,由 Steve Bourne 开发,是第一个流行的 Shell,也是 UNIX上的标准 shell。
    • 现代 Linux 上的 sh 已经被 bash 取代, /bin/sh 往往指向 /bin/bash。
  • bash:全称是 Bourne Again Shell,由 GNU 组织开发,兼容 sh,是各种 Linux 发行版默认配置的 shell。
    • bash 扩展了 sh 的命令和参数,但并不完全兼容 bash,有些行为并不一致。
    • bash 遇到命令失败时,会继续执行下一个命令,除非执行时启用 -e 选项。
  • csh:全称是 C shell,由 Bill Joy 设计,语法类似 C 语言,以此得名。
    • csh 和 bash 的语法不同,二者不能兼容。
    • csh 遇到命令失败时,不会继续执行下一个命令,而是直接停止退出。

1.1.1:查看Shell可用版本

Shell是一个程序,一般放在 /bin 或 /usr/bin 下,当前系统可用的 Shell 都记录在 /etc/shells 文件中。命令 cat /etc/shells 可用查看当前 Linux 系统的可用 Shell:

1.1.2:查看Shell默认版本

命令 echo $0 或者 echo $SHELL 可以查看当前 Linux 系统的默认 Shell。

1.1.3 查看Shell当前版本

命令:ps -p "$$"

1.1.4 切换Shell版本

直接输入:bash 或 csh

1.1.5:申明Shell执行版本

新建一个文件 test.sh,扩展名为 sh (sh 代表 shell ),扩展名并不影响脚本执行,其他名称其实也行。输入代码:

#!/bin/csh -f
echo "Hello World !"
  • 第一行代码即指定该脚本的 shell 解释器版本,运行该脚本时将优先寻找该指定版本,如果 Linux 里没有该指定版本的解释器,或者没有写这一行,则采用默认 Shell 解释器。
  • csh 中会默认先 source $HOME/.cshrc 再执行脚本,-f 参数可以避免这个现象,提高脚本的执行速度。但是注意如果脚本里需要用到一些必须 source .cshrc 才能用的命令( 例如 module ),则加上 -f 参数后,./FileName.sh 方式执行脚本会出错。
  • 如果执行方式是 bash ./test.sh,则强制用 bash 解释器执行该脚本,忽略 #!/bin/csh -f 的作用。

1.2:Shell运行方法

1.2.1:./FileName.sh

./FileName.sh
  • 作用:打开一个子 Shell 读取并执行文件内的命令,不会影响当前 Terminal 下的变量。
  • 注意:建议加上 ./ 符号,避免与其他系统命令冲突。

1.2.2:source ./FileName.sh

source FileName.sh
  • 作用:当前 Terminal 的 Shell 环境下执行文件内的命令,会影响当前 Terminal 下的变量。
  • 注意:该 FileName.sh 可以是无执行权限的。source 在某些环境下可以用命令“ . ”来替代。

1.2.3:sh/csh ./FileName.sh

sh FileName.sh
bash FileName.sh
csh FileName.sh
  • 作用:指定 Shell 解释器版本去执行文件内的命令,会影响当前 Terminal 下的变量。
  • 注意:该 FileName.sh 可以是无执行权限的。除非调试否则不建议这样方执行,因为可能导致使用的解释器和代码内部实际声明的解释器冲突,调试时可以加上 -x 等参数帮助查看问题,见下文。

1.3:Shell调试技巧

1.3.1:调试参数

Shell 本身提供一些调试方法选项,合理运用可以方便我们的调试。

-n:不执行脚本,只检查语法错误。
-u:执行脚本,使用未设置的变量时立即退出脚本,并打印失败变量。(csh 中不可用)
-v:执行脚本,打印原始书写的每行命令和对应执行结果。(bash中还会打印注释)
-x:执行脚本,打印实际执行的每行命令和对应执行结果,例如变量替换后的命令。(bash中的命令前有+号)
-e:执行脚本,打印执行结果,遇到命令失败时立即退出脚本。(csh中本就会失败时退出,因此不适用)

bash 中常用“-uxe”选项,而在 csh 中常常只用到“-x”选项。

1.3.2:调试方法

使用这些选项有三种方法(注意:避免几种调试选项混用)

  1. 命令行提供参数: sh -x script.sh 或者 bash -n script.sh
  2. 脚本头提供参数: #!/bin/sh -x 或者 #!/bin/bash -x
  3. 脚本内用 set 命令:set -x 表示启用,set +x 表示禁用。

最常用的方法是第 1 种,调试前后不需要改动脚本内的代码内容。

2:Shell变量

2.1:创建变量

2.1.1:普通变量

在 shell 中,每一个变量的值都是字符串,无论你给变量赋值时有没有使用引号,值都会以字符串的形式存储。一般来说如果变量值里没有空格、Tab缩进等,那么可以不用引号。使用单引号表示里面是纯字符串,而使用双引号表示里面的变量和命令等需要解析,而不是原样输出。

注意:变量名必须是字母或下划线开头。

#bash 写法,等号左右不能有空格
a=AA
a='A'
a="A"

#csh 写法
set a = AA
set a = 'A'
set a = "A"

2.1.2:命令变量

有时需要给某个变量赋值为某个命令的结果,例如变量 a 赋值为特殊命令 pwd 的结果,格式如下:

#bash 写法
a=`pwd`
a=$(pwd)

#csh 写法
set a = `pwd`

2.1.3:环境变量

环境变量是由操作系统或用户设置的特殊变量,用于配置 Shell 的行为和影响其执行环境。例如 PATH 变量包含了操作系统搜索可执行文件的路径。

#bash 写法
export a=1

#csh 写法
setenv a 1

2.1.4:只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。下面尝试更改只读变量,结果报错:

#bash 写法
a=1
readonly
aa=2

2.1.5:局部变量

shell 脚本中的变量 global 的,作用域从定义开始,到 shell 结束或被删除变量为止。函数定义的变量一般是 local 的,只作用于函数内,如果与 global 变量同名,则函数内的 local 变量会屏蔽 global 变量。

#bash 写法
function Hello()
{
    local a=100
    echo $a
}

2.2:使用变量

使用一个定义过的变量,只要在变量名前加美元符号 $ 即可,外面的花括号 { } 是可选的,当需要识别变量边界时必须加上,其他时候可不加。

使用自定义变量: echo “$a”、echo “${a}”、echo “${a}_${b}”
使用内置变量: echo pwd、echo $(pwd)

注意:csh 中不支持 echo $(pwd)的写法

2.3:删除变量

使用 unset 命令可以删除变量。语法:

unset a

变量被删除后不能再次使用。unset命令不能删除只读变量。

2.4:传递参数

2.4.1:位置参数

运行 Shell 脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用 $n 的形式来接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。同样,在调用函数时也可以这样传递参数,在函数内部也使用 $n 的形式接收。这种通过 $n 的形式来接收的参数,在 Shell 中称为位置参数。其用法如下所示:

#!/bin/bash
echo "name: $1"
echo "age: $2"

运行该 shell 脚本,如下所示:

./test.sh Jack 27

则会输出:

name: Jack
age: 27

2.4.2:特殊变量

位置参数都是数字,这和变量的命名规则是相悖的,所以我们将它们视为“特殊变量”,以下是其他一些特殊变量:

2.4.3:argv 用法

在 csh 中,输入可以用 argv 关键字来获取,将 argv 看成是数组,还能用 # 获取参数个数。在实际的脚本开发中,我们经常用到 argv 关键字处理输入的参数,如下所示:

if($#argv < 3) then
    echo "*Error: pls input 3 argument: param1 param2 param3"
    exit 1
endif
set param1 = $argv[1]
set param2 = $argv[2]
set param3 = $argv[3]

csh 中也可以写成 $1、$2,但是在 bash 中则必须写成 $1、$2 格式:

if [[ $# <3 ]]; then
    echo "*Error: pls input 3 argument: param1 param2 param3"
    exit 1
fi
param1=$1
param2=$2
param3=$3

2.4.4:shift用法

shift 能够将命令接收到的参数逐个向左移动一位,即原本的 $3 变量会覆盖 $2 变量,原本的 $2 变量会覆盖 $1 变量,这样我们只需要每执行一次 shift 命令后调用 $1 变量,就能够实现对全部参数的处理工作了。shift 命令通常用于在不知道传入参数个数的情况下依次遍历每个参数然后进行相应处理,常见于各种程序的启动脚本。例如:

#!/bin/bash
while [ $# != 0 ]
do
    echo -e "参数值为 $1,参数个数为 $#"
    shift
done

执行结果如下所示:

sh test.sh abcd
参数值为 a, 参数个数为 4
参数值为 b, 参数个数为 3
参数值为 c,参数个数为 2
参数值为 d,参数个数为 1

Shift 命令还有另外一个重要用途,Bash 定义了 9 个位置变量,从 $1 到 $9,这并不意味着只能使用 9 个参数,借助 shift 命令可以访问多于 9 个的参数。最后,如果 shift 后面带上参数 n,则每次移动 n 个参数,如 shift 2。在某些脚本中,我还见过这样的用法:使用了输入参数后就加一行 shift 语句来销毁,后面用 foreach xxx ($argv[*]) 时就只剩一个参数了。但我感觉这样的写法很容易出错,没多大意思。

2.5:字符串的技巧

2.5.1:字符串拼接

字符串的拼接非常简单粗暴,如下所示:

set a = "A"
set b = "B"
set str1 = $a$b          #中间不能有空格
set str2 = "$a: $b"      #如果被双引号包围,那么中间可以有空格
set str3 = "${a}hhhh $b" #为免误认,加上大括号标识边界

2.5.2:字符串截取

2.5.3:字符串长度

也许有时需要获取字符串的长度,格式如下所示:

${#string_name}

2.6:数组变量(进阶)

数组中可以存放多个值,Bash 只支持一维数组,初始化时不需要定义数组大小,数组元素的下标由 0 开始。

2.6.1:数组

创建语法格式如下:

#bash 写法
array=(0 1 2)
或者
array[0]=0
array[1]=1
array[2]=2

#csh 写法
set array = (0 1 2) //也可以是(0,1, 2)
或者
set array[0] = 0
set array[1] = 1
set array[2] = 2

2.6.2:数组使用

#bash 写法
array=(A B "C")
echo "第一个元素为:${array[0]}"
echo "所有的元素为: ${array[*]}"
echo "所有的元素为:${array[@]}"

#csh 写法
set array = (A B "C")
echo "第一个元素为: ${array[0]}"
echo "所有的元素为:${array[*]}"

2.6.3:数组删除

在 Shell 中使用 unset 关键字来删除数组元素,具体格式如下:

unset array[1]

如果不写下标,而是写成下面的形式:

unset array

那么就是删除整个数组,所有元素都会消失。

2.6.4:数组拼接

所谓 Shell 数组拼接(数组合并),就是将两个数组连接成一个数组。将数组扩展成列表再合并到一起就行了。

#bash 写法
array_new=(${array1[@]} ${array2[@]})
array_new=(${array1[*]} ${array2[*]})

#csh 写法
set array_new = (${array1[@]} ${array2[@]})
set array_new = (${array1[*]} ${array2[*]})

2.6.5:数组长度

和字符串的技巧一样,加个 # 就行了,如下所示:

${#array[@]}
${#array[*]}
${#array[2]}

2.6.6:关联数组

略,键值对什么的,没遇到过,遇到了要用再说。

3:Shell运算

Shell和其他编程语言一样,支持多种运算符,包括:

  • 算数运算符
  • 关系运算符
  • 布尔运算符
  • 字符串运算符
  • 文件测试运算符

原生 bash 不支持简单的数学运算,但是可以通过其他命令来实现。

3.1:数学运行命令

3.1.1:(( )) --bash

双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,内部变量不需要用到 $,非常干净整洁。

((表达式))

表达式可以只有一个,也可以有多个,多个表达式之间以逗号 , 分隔。对于多个表达式的情况,以最后一个表达式的值作为整个命令的执行结果。使用 $ 获取 (()) 命令的结果,也可以先赋值给变量,再用 $ 获得该变量值。

#--------------------- 例 1
echo $((1+1))
结果是:2
#--------------------- 例 2
a=1
((b=a+2))
echo $b
结果是:3
#--------------------- 例 3
a=1
b=$((a+3))
echo $b
结果是:4
#--------------------- 例 4
c=$((1+1, a=2+3, b=4+5))
echo $a $b $c
结果是:5,9,9

3.1.2:@ --csh

csh 中的计算多用“@”,注意 @ 后面有一个空格,案例如下:

#--------------------- 例 1
@а = 1+ 1
echo $a
结果是:2
#--------------------- 例 2
set a = 1
@ b = $b + 3
# @b = $b + 3 #Invalid
# @ b = $b+3 #Invalid
echo $b
结果是:4

如果希望 echo 里面直接计算,那用 bc 命令即可,如:

set a = 1
echo "$a+1"|bc
结果是:2 

3.2:数学运算符

 基本的数学运算符,没什么好说的。

3.3:数字比较运算符

 在 test 命令格式的 [ expr ] 内必须写成这类符号,而如果是 ((expr)) 则可以写成 >、< 等符号。

3.4:字符关系运算符

 csh 中,字符串测试相等是“==”和“!=”;模式匹配测试不相等是“=~”“!~”。

3.5:文件测试运算符

3.6:布尔运算符

3.7:逻辑运算符

 4:Shell打印

将执行结果打印到屏幕上,是非常重要的调试技巧,常用的打印命令有 echo 和 print。

4.1:echo

echo 是一个内建命令,用来在终端输出字符串,会在最后默认加上换行符。echo 参数很多,只挑 3 点讲讲。

4.1.1:引号区别

echo 后面的内容是无引号、单引号还是双引号,结果不一样。

总结如下:

  • 单引号得形,双引号得值,无引号得值。
  • 单双-双单混用,留其引号。
  • 单单-双双叠加,去其引号。

大部分情况下,我们都希望里面的获得变量的值,而不是 $a 这种字符,因此双引号用得比较多。如果在双引号的包围下又想获得 $a 这种字符,那么可以再加一层双引号和单引号。可以这样记:加双引号相当于去掉了外层的双引号,那么再加单引号就能得到其形 $a,如上图中最后的""'$a'""

4.1.2:不想换行(-n)

echo 命令输出结束后默认会换行,如果不希望换行,可以加上 -n 参数,如下所示:

echo -n "Hello "
echo -n "World "
echo "!"

执行结果为: 

Hello World !

4.1.3:需要转义(-e)

bash 中的 echo 不会解析以反斜杠 \ 开头的转义字符。比如 \n 表示换行, \c 表示不换行。echo 默认会将它作为普通字符对待。我们可以添加 -e 参数来让 echo 命令解析转义字符。例如:

echo -e "Hello\nWorld !"

执行结果为:

Hello
World !

注意:csh 中的 echo 能够解析以反斜杠 \ 开头的转义字符,不需要加 -e。

4.1.4: 特殊技巧(csh)

除了前面几点,csh 中的 echo 还有一些特殊技巧,如下所示:

4.2:printf

除了 echo 外,还有一个 printf 命令可以用来打印,printf 命令不会默认添加换行符。printf 使用引用文本或空格分隔的参数,外面可以在 printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。格式如下:

printf string
printf 'string'
printf "string"
printf "I am %d cm." 224
#get: I am 224 cm.

4.3: /dev/null

如果某条指令原本会在屏幕上打印(例如sort),但是我们不希望它打印,则可以将其重定向到 /dev/null。

sort test.txt > /dev/null

5:Shell流控

5.1:条件表达式

5.1.1:if-else(( expr ))

if (( $a == $b )); then
    echo "a和b相等“
fi
if (( $age <= 2 )); then
    echo "婴儿"
elif (( $age >= 3 && $age <= 8 )); then
    echo "幼儿"
elif (( $age >= 9 && $age <= 17 )); then
    echo "少年"
elif (( $age >= 18 && $age <=25 )); then
    echo "成年"
elif (($age >= 26 && Sage <= 40 )); then
    echo "青年"
elif (($age >= 41 && $age <= 60 )); then
    echo "中年"
else
    echo "老年"
fi

注意:((expr))内可以用 >、>= 等符号。

5.1.2:if-else[ expr ]

test 是 Shell 内置命令,用来检测某个条件是否成立。test 通常和 if 语句一起使用,并且大部分 if 语句都依赖 test。Shell 中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。test 有两种形态,一种是写作 test expr,一种是写作 [ expr ],注意空格不能省略。

if test $age -le 2; then
    echo "婴儿"
elif test $age -ge 3 && test $age -le 8; then
    echo "幼儿"
elif [ $age -ge 9 ] && [ $age -le 17]; then
    echo "少年"
elif test $age -ge 18 && [ $age -le 25 ]; then
    echo "成年"
else
    echo "老年"
fi

注意: [expr] 内不能用 >、>= 等符号。

学习 test 命令,重点是学习它的各种选项,如下所示:

cd /bin
if test -e ./bash
then
    echo '文件已存在!'
else
    echo '文件不存在!'
fi

test 中使用的变量建议用双引号包起来,否则如果变量是空字符串,则程序会报错。

5.1.3:if-else[[ expr ]]

[[ ]] 是 Shell 内置关键字,它和 test 命令类似,可以认为 [[ ]]test 的升级版。

  • [[ ]] 支持空字符串,所以变量不需要双引号包起来。
  • [[ ]]支持 >、< 等符号。
  • [[ ]] 支持逻辑运算符 &&、|、!。
  • [[ ]]支持正则表达式。

总而言之,[[ ]] [ ] 更强大,更好用!

5.1.4: if-else (csh)

csh 中的 if-else 用法和前面 3 种 bash 的类似,格式如下:

if(a != b) then
    echo "ok"
endif

文件操作:

if( -e file $$ -d file ) then
    echo "file exists and is a directory"
endif

如果不存在,可以这样写:(也可以 ! 放到括号里)。

if !($?SIM_ENV) then
    setenv SIM_ENV ${PRJ}_SIM
endif

需要和多个字符相比较,例如 file 是否是 *log 或 log* 的文件,特别注意大括号里面没有空格。

if ($file =~ {*log,log*}) then
    #......
endif

5.1.5:goto

if ($#argv == 0) then
    goto Label
endif

Label:
    echo "Script $0 needs argument"
    exit 2

5.1.6:case

bash:case in

case $num in
    1)
        echo "data 1"
        ;;
    2)
        echo "data 2"
        ;;
    3)
        echo "data 3"
        ;;
    4)
        echo "data 4"
        ;;
    5)
        echo "data 5"
        ;;
    *)
        echo "error"
esac

csh:switch case

switch ( $word )
case str_1:
    [comands]
    breaksw
...
case str_n:
    [commands]
    breaksw
default:
    [commands]
    breaksw
endsw
#word为控制变量,breaksw跳出switch操作

5.2:循环表达式

5.2.1:while

bash:

while ( true )
do
    echo "ok"
done

csh:

while(1)
    echo "ok"
end

5.2.2:until

与 while 相反,条件不成立时才循环,且优先级小于 while,很少使用。

until ((i > 100))
do
    ((sum += i))
    ((i++))
done

5.2.3:for(foreach)

bash:for

for ((i=1; i<=100; i++))
do
    ((sum += i))
done

bash:for in

还有一种 for-in 结构,每次循环都会从后面列表中取出一个值赋给前面的变量,然后进入循环体,直到取完列表中的所有值,循环就结束了。

sum=0
for n in 1 2 3 4 5 6
do
    echo $n
    ((sum+=n))
done

echo "The sum is $sum"

 csh:foreach

foreach arg ($*)
    echo "the argument: $arg"
end

5.2.4:select in

echo "What is your favourite OS?"
select name in "Linux" "Windows" "Mac OS" "UNIX" "Android" 
do
    echo $name
done
    echo "You have selected $name"

5.2.5:repeat

while ( 1 )
    echo "Hello, in 1st loop..."
    while ( 1 )
        echo "Hello, in 2nd loop..."
        while ( 1 )
            echo "Hello, in 3rd loop..."
            repeat 3 break
        end
    end
end

5.2.6:break和continue

使用 while、until、for、select 循环时,如果想提前结束循环(在不满足结束条件的情况下结束循环),可以使用 break 或者 continue 关键字。break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环。

break

sum=0
while read n; do
    if((n>0)); then
        ((sum+=n))
    else
        break
    fi
done

continue

while read n; do
    if((n<1 II n>100)); then
        continue
    fi
        ((sum+=n))
done

6:Shell函数

只有 bash 才有函数,csh中没有函数的概念,如有需要可以用 alias 语法。

6.1:function(bash)

6.1.1:不带参数

[ function ] funcName [()]
{
    action;
    [return int;]
}

中括号框起来的部分,都是可以省略的部分。

funWithReturn()
{
    echo "这个函数会对输入的两个数字进行相加运算….."
    echo "输入第一个数字:"
    read aNum
    echo "输入第二个数字:"
    read anotherNum
    echo "两个数字分别为 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"

输出如下:

这个函数会对输入的两个数字进行相加运算...
输入第一个数字:
1
输入第二个数字:
2
两个数字分别为 1 和 2 !
输入的两个数字之和为 3 !

函数返回值在调用该函数后通过 $? 来获得。

注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至 shell 解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。

6.1.2:携带参数

在Shell中,调用函数时可以向其传递参数。在函数体内部通过 $n 的形式来获取参数的值,例如 $1 表示第一个参数,$2 表示第二个参数...

带参数的函数示例:

funwithParam()
{
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

输出结果:

第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !

注意,$10 不能获取第十个参数,获取第十个参数需要${10}。当 n>=10 时,需要使用 ${n} 来获取参数。这边需要再注意一下,之前提过的一些特殊变量用法:

6.2:alias(csh)

csh 中没有函数的概念,但是可以用 alias 达到函数的目的:

alias func 'echo \!:1 \!:2 \!:*’
func 1 2 3 4 5

alias 参数处理:第一个参数 \!:1,最后一个参数 \!$,所有参数 \!:*。

7:Shell三剑客

7.1:grep

可以直接看前面的博客《Linux常用技巧》,如下所示:

grep 命令用于查找文件里的字符,会在屏幕上打印出匹配字符的那行文本。语法:grep 字符 [path]

  • [path]:指定路径,加了-r后可以省略,省略则表示指定为当前路径。
  • -r:递归查找指定path及其子目录下的所有文件。
  • -i:不区分大小写。
  • -n:打印出匹配行的行号。
  • -l:只打印匹配的文件名。
  • -v:反向查找,只打印不匹配的行。
  • -E "字符a|字符b":查找字符a或字符b,符号 | 前后不能有空格。

我想先用 find 命令查找到所需文件,然后在这些文件里查找所需字符在哪里,那么 find 命令和 grep 命令结合可以达到效果。方法是采用命令”|xargs“,解释见上文说明。

7.2:sed

Linux sed 命令是利用脚本来处理文本文件。sed 是一种流编辑器,它是文本处理中非常好的工具,能够完美的配合正则表达式使用,功能不同凡响。处理时把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。sed 主要用来自动编辑一个或多个文件,可以将数据行进行替换、删除、新增、选取等特定工作,简化对文件的反复操作,编写转换程序等。菜鸟网讲的不好,可以查阅博客:Linux之sed命令详解

7.3:awk

比较复杂,有时间再学~

8:Shell其他命令和技巧

8.1:read输入

bash 中用到过,简单理解为从键盘读取数据,不多说,看例子:

read -p "Pls input value of a, b, c: " a b c 
echo $a $b $c

Terminal 上运行脚本后会停住,需要我们输入 3 个值,输入完成后按回车,脚本继续运行,内容如下:

Pls input value of a, b, c: 111 233 456
111 233 456

8.2:exit退出

exit 表示程序退出,并提供可指定的返回值,如果没有指定返回值,则默认返回值为 0 表示命令成功执行,1 表示命令出现错误。exit 可以和 $? 配合使用,帮助我们 debug。例如在代码中写上:

if [[ $# < 3 ]]; then
    echo "input argument is less then 3" 
    exit 3
fi

然后在 Terminal 中输入:

$ bash ./test.sh
$ input argument is less then 3
$ echo $#
$ 3

执行shell脚本后,再执行 echo$# 命令,即可获得脚本退出时的 exit 返回值,从而确定是哪段命令出现了错误。

8.3:data时间戳

有时需要用上时间参数 data,例如在处理文件时加上时间戳,可以帮助我们保存不同版本的文件。代码如下:

set timeStamp = `date +%Y%m%d_%HM`
cp -rf dirl/file.txt dir2/file_${timeStamp}.txt

8.4:pwd当前目录

有时需要获得当前目录,然后利用目录再进行一些文件操作,可以用上 pwd 命令,如下所示:

set a = `pwd`
echo $a

如果再用上一些 echo 的技巧,则可以从目录中取出更简洁的信息,如下所示:

8.5:if多个比较

判断某个文件是否是 log文件,特征点可能有多种,csh 中可以写成下面这样:

set file = test.log

if ($file =~ {*log,log*}) then
    echo "file is log file"
else
    echo "file is not log file"
endif

注意大括号里面不能有空格,否则出错。

8.6:Shell中添加彩色字符

可以查阅文章:shell bash终端中输出的颜色和格式详解(超详细)

 

参考资料:

[1] https://www.runoob.com/linux/linux-shell.html

[2] https://c.biancheng.net/shell/

[3] https://sunner.cn/courses/OS/Learning_UNIX.pdf

[4] shell bash终端中输出的颜色和格式详解(超详细)

[5] Linux之sed命令详解

posted @ 2023-12-31 16:24  咸鱼IC  阅读(851)  评论(0编辑  收藏  举报