bash脚本常用命令篇

178 阅读5分钟

Bash常用命令

查看当前运行的 Shell

echo $SHELL

查看当前的 Linux 系统安装的所有 Shell

cat /etc/shells

-e参数会解释引号(双引号和单引号)里面的特殊字符

echo -e 'Hello\nWorld’  
echo "Hello\nWorld" -》Hello\nWorld

-n参数可以取消末尾的回车符

echo -n a ; 
echo b -> ab 

分号(;)是命令的结束符,使得一行可以放置多个命令

clear; ls

如果Command1命令运行成功,则继续运行Command2命令。

Command1 && Command2

cat filelist.txt && ls -l filelist.txt

如果Command1命令运行失败,则继续运行Command2命令。

Command1 || Command2

mkdir foo || mkdir bar

波浪线~会自动扩展成当前用户的主目录

echo ~  ->   /home/me

?字符代表文件路径里面的任意单个字符,不包括空字符

 ls ?.txt -> a.txt b.txt

*字符代表文件路径里面的任意数量的字符,包括零个字符

ls *.txt -> a.txt b.txt ab.txt

方括号扩展的形式是[...],只有文件确实存在的前提下才会扩展。如果文件不存在,就会原样输出。

ls [ab].txt -> a.txt b.txt

[^...]和[!...]。它们表示匹配不在方括号里面的字符

ls ?[!a]? -> aba  bbb

方括号扩展有一个简写形式[start-end],表示匹配一个连续的范围

ls [a-c].txt -》 a.txt  b.txt c.txt 
echo report[!1–3].txt -> report4.txt report5.txt

大括号扩展{...}表示分别扩展成大括号里面的所有值,各个值之间使用逗号分隔

echo {1,2,3} -> 1 2 3   ls {a, b, c}.txt  
cp a.log{,.bak} -> cp a.log a.log.bak
echo a{A{1,2},B{3,4}}b -> aA1b aA2b aB3b aB4b
echo {cat , d*} -> cat dawg dg dig dog dug
mkdir {2007..2009}-{01..12} -> 上面命令会新建36个子目录,每个子目录的名字都是”年份-月份“
echo {0..8..2} -> 0 2 4 6 8

Bash 将美元符号$开头的词元视为变量,将其扩展成变量值

 echo $SHELL
 echo ${SHELL}
${!string*}${!string@}返回所有匹配给定字符串string的变量名。

echo ${!S*} 
SECONDS SHELL SHELLOPTS SHLVL SSH_AGENT_PID SSH_AUTH_SOCK

$(...)可以扩展成另一个命令的运行结果,该命令的所有输出都会作为返回值    

echo $(date)

$((...))可以扩展成整数运算的结果,详见《Bash 的算术运算》一章。

echo $((2 + 2)) -> 4
[[:class:]]表示一个字符类,扩展成某一类特定字符之中的一个

echo [[:upper:]]*    输出所有大写字母开头的文件名

echo [![:digit:]]*     输出所有不以数字开头的文件名

量词语法有下面几个

-   ?(pattern-list):匹配零个或一个模式。
-   *(pattern-list):匹配零个或多个模式。
-   +(pattern-list):匹配一个或多个模式。
-   @(pattern-list):只匹配一个模式。
-   !(pattern-list):匹配零个或一个以上的模式,但不匹配单独一个的模式
ls abc?(.)txt   -> abctxt  abc.txt. 
ls abc?(def) -> abc abcdef
ls abc+(.txt|.php) -> abc.php abc.txt

反斜杠除了用于转义,还可以表示一些不可打印的字符

 echo a\tb -> atb 
 echo -e "a\tb" -> a        b

单引号用于保留字符的字面含义,各种特殊字符在单引号里面,都会变为普通字符,比如星号(*)、美元符号($)、反斜杠(\)等

echo '$USER' -> $USER  
echo '$((2+2))’->$((2+2)) 
echo '$(echo foo)'  -> $(echo foo)
双引号比单引号宽松,可以保留大部分特殊字符的本来含义,但是三个字符除外:美元符号($)、反引号(`)和反斜杠(\)

Bash变量分成环境变量和自定义变量两类 自定义变量是用户在当前 Shell 里面自己定义的变量,必须先定义后使用,而且仅在当前 Shell 可用。一旦退出当前 Shell,该变量就不存在了

echo $PATH 

Bash 没有数据类型的概念,所有的变量值都是字符串。

echo ${a}_file

unset命令用来删除一个变量

unset NAME

用户创建的变量仅可用于当前 Shell,子 Shell 默认读取不到父 Shell 定义的变量。为了把变量传递给子 Shell,需要使用export命令。这样输出的变量,对于子 Shell 来说就是环境变量,子Shell如果修改继承的变量,不会影响父 Shell

特殊变量

(1) $?  为上一个命令的退出码,用来判断上一个命令是否执行成功。返回值是0,表示上一个命令执行成功;如果是非零,上一个命令执行失败

(2) $$  为当前 Shell 的进程 ID

(3) $_  为上一个命令的最后一个参数  grep dictionary /usr/share/dict/words        echo $_  ->  /usr/share/dict/words

(4) $!   为最近一个后台执行的异步命令的进程 ID

(5) $0为当前 Shell 的名称(在命令行直接执行时)或者脚本名(在脚本中执行时)

(6) $-为当前 Shell 的启动参数。

变量的默认值

如果变量varname存在且不为空,则返回它的值,否则返回word    -> ${varname:-word}

如果变量varname存在且不为空,则返回它的值,否则将它设为word,并且返回word   -> ${varname:=word}

如果变量名存在且不为空,则返回word,否则返回空值. ${varname:+word}

如果变量varname存在且不为空,则返回它的值,否则打印出varname: message,并中断脚本的执行。如果省略了message,则输出默认的信息“parameter null or not set.”。它的目的是防止变量未定义,比如${count:?"undefined!"}表示变量count未定义时就中断执行,抛出错误,返回给定的报错信息undefined!    ${varname:?message}

declare命令可以声明一些特殊类型的变量,为变量设置一些限制

-   -a:声明数组变量。
-   -f:输出所有函数定义。
-   -F:输出所有函数名。
-   -i:声明整数变量。
-   -l:声明变量为小写字母。
-   -p:查看变量信息。
-   -r:声明只读变量。
-   -u:声明变量为大写字母。
-   -x:该变量输出为环境变量。

declare命令如果用在函数中,声明的变量只在函数内部有效,等同于local命令。

不带任何参数时,declare命令输出当前环境的所有变量,包括函数在内,等同于不带有任何参数的set命令。

declare -i val1=12 val2=5

declare -i result

result=val1*val2

echo $result

60
$ declare -x foo

# 等同于

$ export foo

let命令声明变量时,可以直接执行算术表达式

获取字符串长度的语法. -> ${#varname}  
myPath=/home/cam/book/long.file.name -> echo ${#myPath}

字符串提取子串的语法如下 ->
${varname:offset:length}. 
count=frogfootman   
echo ${count:4:4}

字符串头部的模式匹配

删除最短匹配(非贪婪匹配)的部分,返回剩余部分. ${variable#pattern}

删除最长匹配(贪婪匹配)的部分,返回剩余部分. ${variable##pattern}

myPath=/home/cam/book/long.file.name 

echo ${myPath#/*/}. -> cam/book/long.file.name.    

echo ${myPath##/*/} -> long.file.name

字符串尾部的模式匹配。

删除最短匹配(非贪婪匹配)的部分,返回剩余部分  {variable%pattern}
删除最长匹配(贪婪匹配)的部分,返回剩余部分 {variable%%pattern}
path=/home/cam/book/long.file.name.     
echo ${path%.*} -> /home/cam/book/long.file        
echo ${path%%.*} -> /home/cam/book/long

任意位置的模式匹配

最长匹配(贪婪匹配)的那部分被 string 替换,但仅替换第一个匹配     {variable/pattern/string}
最长匹配(贪婪匹配)的那部分被 string 替换,所有匹配都替换     {variable//pattern/string}
path=/home/cam/foo/foo.name   
echo ${path/foo/bar} -> /home/cam/bar/foo.name          
echo ${path//foo/bar} -> /home/cam/bar/bar.name

((...))语法可以进行整数的算术运算 expr命令支持算术运算,可以不使用((...))语法。 Bash 内置了 Readline 库,具有这个库提供的很多“行操作”功能,比如命令的自动补全,可以大大加快操作速度。 Bash 脚本入门 Shebang 行不是必需的,但是建议加上这行。如果缺少该行,就需要手动将脚本传给解释器。举例来说,脚本是script.sh,有 Shebang 行的时候,可以直接调用执行

 ./script.sh
 如果没有 Shebang 行,就只能手动将脚本传给解释器来执行
 /bin/sh ./script.sh    
 bash ./script.sh

只要指定了 Shebang 行的脚本,可以直接执行。这有一个前提条件,就是脚本需要有执行权限。可以使用下面的命令,赋予脚本执行权限。

给所有用户执行权限

$ chmod +x script.sh

给所有用户读权限和执行权限

$ chmod +rx script.sh

或者

$ chmod 755 script.sh

只给脚本拥有者读权限和执行权限

$ chmod u+rx script.sh

脚本的权限通常设为755(拥有者有所有权限,其他人有读和执行权限)或者700(只有拥有者可以执行)

除了执行权限,脚本调用时,一般需要指定脚本的路径(比如path/script.sh)。如果将脚本放在环境变量$PATH指定的目录中,就不需要指定路径了。因为 Bash 会自动到这些目录中,寻找是否存在同名的可执行文件。

建议在主目录新建一个~/bin子目录,专门存放可执行脚本,然后把~/bin加入$PATH。

export PATH=$PATH:~/bin
上面命令改变环境变量$PATH,将~/bin添加到$PATH的末尾。
可以将这一行加到~/.bashrc文件里面,然后重新加载一次.bashrc,这个配置就可以生效了

脚本参数

    script.sh word1 word2 word3
-   $0:脚本文件名,即script.sh。
-   $1~$9:对应脚本的第一个参数到第九个参数。
-   $#:参数的总数。
-   $@:全部的参数,参数之间使用空格分隔。
-   $*:全部的参数,参数之间使用变量$IFS值的第一个字符分隔,默认为空格,但是可以自定义。

source命令用于执行一个脚本,通常用于重新加载一个配置文件

source命令最大的特点是在当前 Shell 执行脚本,不像直接执行脚本时,会新建一个子 Shell。所以,source命令执行脚本时,不需要export变量。

#!/bin/bash
echo -n "输入一个1到3之间的数字(包含两端)> "
read character
if [ "$character" = "1" ]; then
    echo 1
elif [ "$character" = "2" ]; then
    echo 2
elif [ "$character" = "3" ]; then
    echo 3
else
    echo 输入不符合要求
fi
if test -e /tmp/foo.txt ; then
  echo "Found foo.txt"
fi

if [ -e /tmp/foo.txt ] ; then
  echo "Found foo.txt"
fi


if [[ -e /tmp/foo.txt ]] ; then
  echo "Found foo.txt"
fi
  

文件判断:

-   [ -a file ]:如果 file 存在,则为true。
-   [ -b file ]:如果 file 存在并且是一个块(设备)文件,则为true。
-   [ -c file ]:如果 file 存在并且是一个字符(设备)文件,则为true。
-   [ -d file ]:如果 file 存在并且是一个目录,则为true。
-   [ -e file ]:如果 file 存在,则为true。
-   [ -f file ]:如果 file 存在并且是一个普通文件,则为true。
-   [ -g file ]:如果 file 存在并且设置了组 ID,则为true。
-   [ -G file ]:如果 file 存在并且属于有效的组 ID,则为true。
-   [ -h file ]:如果 file 存在并且是符号链接,则为true。
-   [ -k file ]:如果 file 存在并且设置了它的“sticky bit”,则为true。
-   [ -L file ]:如果 file 存在并且是一个符号链接,则为true。
-   [ -N file ]:如果 file 存在并且自上次读取后已被修改,则为true。
-   [ -O file ]:如果 file 存在并且属于有效的用户 ID,则为true。
-   [ -p file ]:如果 file 存在并且是一个命名管道,则为true。
-   [ -r file ]:如果 file 存在并且可读(当前用户有可读权限),则为true。
-   [ -s file ]:如果 file 存在且其长度大于零,则为true。
-   [ -S file ]:如果 file 存在且是一个网络 socket,则为true。
-   [ -t fd ]:如果 fd 是一个文件描述符,并且重定向到终端,则为true。 这可以用来判断是否重定向了标准输入/输出错误。
-   [ -u file ]:如果 file 存在并且设置了 setuid 位,则为true。
-   [ -w file ]:如果 file 存在并且可写(当前用户拥有可写权限),则为true。
-   [ -x file ]:如果 file 存在并且可执行(有效用户有执行/搜索权限),则为true。
-   [ file1 -nt file2 ]:如果 FILE1 比 FILE2 的更新时间最近,或者 FILE1 存在而 FILE2 不存在,则为true。
-   [ file1 -ot file2 ]:如果 FILE1 比 FILE2 的更新时间更旧,或者 FILE2 存在而 FILE1 不存在,则为true。
-   [ FILE1 -ef FILE2 ]:如果 FILE1 和 FILE2 引用相同的设备和 inode 编号,则为true。

字符串判断:

-   [ string ]:如果string不为空(长度大于0),则判断为真。
-   [ -n string ]:如果字符串string的长度大于零,则判断为真。
-   [ -z string ]:如果字符串string的长度为零,则判断为真。
-   [ string1 = string2 ]:如果string1和string2相同,则判断为真。
-   [ string1 == string2 ] 等同于[ string1 = string2 ]。
-   [ string1 != string2 ]:如果string1和string2不相同,则判断为真。
-   [ string1 '>' string2 ]:如果按照字典顺序string1排列在string2之后,则判断为真。
-   [ string1 '<' string2 ]:如果按照字典顺序string1排列在string2之前,则判断为真。
#!/bin/bash

number=0
while [ "$number" -lt 10 ]; do
  echo "Number = $number"
  number=$((number + 1))
done

启动的初始化脚本依次如下

-   /etc/profile:所有用户的全局配置脚本。
-   /etc/profile.d目录里面所有.sh文件
-   ~/.bash_profile:用户的个人配置脚本。如果该脚本存在,则执行完就不再往下执行。
-   ~/.bash_login:如果~/.bash_profile没找到,则尝试执行这个脚本(C shell 的初始化脚本)。如果该脚本存在,则执行完就不再往下执行。
-   ~/.profile:如果~/.bash_profile和~/.bash_login都没找到,则尝试读取这个脚本(Bourne shell 和 Korn shell 的初始化脚本)。

非登录 Session 的初始化脚本依次如下。

-   /etc/bash.bashrc:对全体用户有效。
-   ~/.bashrc:仅对当前用户有效。
-eq 等于   -ne 不等于   -gt 大于  -lt 小于   -ge 大于等于   -le 小于等于