查看“Shell new”的源代码
←
Shell new
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
=== 简介 === ==== 什么是 shell ==== * Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。 * Shell 既是一种命令语言,又是一种程序设计语言。 * Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问 Linux 内核的服务。 ==== 什么是 shell 脚本 ==== Shell 脚本(shell script),是一种为 shell 编写的脚本程序,一般文件后缀为 <code>.sh</code>。 ==== shell 环境 ==== shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。 shell 的解释器种类众多,常见的有: sh - 即 Bourne Shell。sh 是 Unix 标准默认的 shell。 bash - 即 Bourne Again Shell。bash 是 Linux 标准默认的 shell。 fish - 智能和用户友好的命令行 shell。 xiki - 使 shell 控制台更友好,更强大。 zsh - 功能强大的 shell 与脚本语言。 ==== 模式 ==== ===== 交互模式 ===== ===== 非交互模式 ===== === 基本语法 === ==== 解释器 ==== ==== 注释 ==== ==== echo ==== echo 用于字符串的输出。 * 输出普通字符串:<syntaxhighlight lang="shell"> echo "hello, world" # Output: hello, world </syntaxhighlight> * 输出含变量的字符串:<syntaxhighlight lang="shell"> name=xiaoming echo "hello, \"${name}\"" # Output: hello, "xiaoming" </syntaxhighlight> * 输出含换行符的字符串:<syntaxhighlight lang="shell"> # 输出含换行符的字符串 echo "YES\nNO" # Output: YES\nNO echo -e "YES\nNO" # -e 开启转义 # Output: # YES # NO </syntaxhighlight> * 输出含不换行符的字符串:<syntaxhighlight lang="shell"> echo "YES" echo "NO" # Output: # YES # NO echo -e "YES\c" # -e 开启转义 \c 不换行 echo "NO" # Output: # YESNO </syntaxhighlight> * 输出重定向至文件:<syntaxhighlight lang="shell"> echo "test" > test.txt </syntaxhighlight> * 输出执行结果:<syntaxhighlight lang="shell"> echo `pwd` # Output:(当前目录路径) </syntaxhighlight> ==== printf ==== printf 用于格式化输出字符串。 printf 命令的语法: printf format-string [arguments...] 参数说明: * '''format-string:''' 为格式控制字符串 * '''arguments:''' 为参数列表。 默认,printf 不会像 echo 一样自动添加换行符,如果需要换行可以手动添加 <code>\n</code>。 === 变量 === 跟许多程序设计语言一样,你可以在 bash 中创建变量。 bash 中没有数据类型,bash 中的变量可以保存一个数字、一个字符、一个字符串等等。同时无需提前声明变量,给变量赋值会直接创建变量。 ==== 变量命名原则 ==== * 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。 * 中间不能有空格,可以使用下划线(_)。 * 不能使用标点符号。 * 不能使用 bash 里的关键字(可用 help 命令查看保留关键字)。 ==== 声明变量 ==== 访问变量的语法形式为:<code>${var}</code> 和 <code>$var</code> 。 变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,所以推荐加花括号。<syntaxhighlight lang="shell"> word="hello" echo ${word} # Output: hello </syntaxhighlight> ==== 只读变量 ==== 使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。<syntaxhighlight lang="shell"> rword="hello" echo ${rword} readonly rword # rword="bye" # 如果放开注释,执行时会报错 </syntaxhighlight> ==== 删除变量 ==== 使用 unset 命令可以删除变量。变量被删除后不能再次使用。unset 命令不能删除只读变量。<syntaxhighlight lang="shell"> dword="hello" # 声明变量 echo ${dword} # 输出变量值 # Output: hello unset dword # 删除变量 echo ${dword} # Output: (空) </syntaxhighlight> ==== 变量类型 ==== * '''局部变量''' :局部变量是仅在某个脚本内部有效的变量。它们不能被其他的程序和脚本访问。 * '''环境变量''' :环境变量是对当前 shell 会话内所有的程序或脚本都可见的变量。创建它们跟创建局部变量类似,但使用的是 <code>export</code> 关键字,shell 脚本也可以定义环境变量。 常见的环境变量: {| class="wikitable" !变量 !描述 |- |<code>$HOME</code> |当前用户的用户目录 |- |<code>$PATH</code> |用分号分隔的目录列表,shell 会到这些目录中查找命令 |- |<code>$PWD</code> |当前工作目录 |- |<code>$RANDOM</code> |0 到 32767 之间的整数 |- |<code>$UID</code> |数值类型,当前用户的用户 ID |- |<code>$PS1</code> |主要系统输入提示符 |- |<code>$PS2</code> |次要系统输入提示符 |} === 字符串 === ==== 单引号和双引号 ==== shell 字符串可以用单引号 <code><nowiki>''</nowiki></code>,也可以用双引号 <code>“”</code>,也可以不用引号。 * 单引号的特点 ** 单引号里不识别变量 ** 单引号里不能出现单独的单引号(使用转义符也不行),但可成对出现,作为字符串拼接使用。 * 双引号的特点 ** 双引号里识别变量 ** 双引号里可以出现转义字符 综上,推荐使用双引号。 ==== 拼接字符串 ==== <syntaxhighlight lang="shell"> # 使用单引号拼接 name1='white' str1='hello, '${name1}'' str2='hello, ${name1}' echo ${str1}_${str2} # Output: # hello, white_hello, ${name1} # 使用双引号拼接 name2="black" str3="hello, "${name2}"" str4="hello, ${name2}" echo ${str3}_${str4} # Output: # hello, black_hello, black </syntaxhighlight> ==== 获取字符串长度 ==== <syntaxhighlight lang="shell"> text="12345" echo ${#text} # Output: # 5 </syntaxhighlight> ==== 截取子字符串 ==== <syntaxhighlight lang="shell"> text="12345" echo ${text:2:2} # Output: # 34 </syntaxhighlight> ==== 查找子字符串 ==== <syntaxhighlight lang="shell"> text="hello" echo `expr index "${text}" ll` #查找 ll 子字符在 hello 字符串中的起始位置。 # Output: # 3 </syntaxhighlight> === 数组 === bash 只支持一维数组。数组下标从 0 开始,下标可以是整数或算术表达式,其值应大于或等于 0。 ==== 创建数组 ==== <syntaxhighlight lang="shell"> # 创建数组的不同方式 nums=([2]=2 [0]=0 [1]=1) colors=(red yellow "dark blue") </syntaxhighlight> ==== 访问数组元素 ==== * 访问数组的单个元素: <syntaxhighlight lang="shell"> echo ${nums[1]} # Output: 1 </syntaxhighlight> * 访问数组的所有元素: <syntaxhighlight lang="shell"> echo ${colors[*]} # Output: red yellow dark blue echo ${colors[@]} # Output: red yellow dark blue </syntaxhighlight> * 访问数组的部分元素: <syntaxhighlight lang="shell"> echo ${nums[@]:0:2} # Output: # 0 1 </syntaxhighlight>在上面的例子中,<code>${array[@]}</code> 扩展为整个数组,<code>:0:2</code>取出了数组中从 0 开始,长度为 2 的元素。 ==== 访问数组长度 ==== <syntaxhighlight lang="shell"> echo ${#nums[*]} # Output: # 3 </syntaxhighlight> ==== 向数组中添加元素 ==== <syntaxhighlight lang="shell"> colors=(white "${colors[@]}" green black) echo ${colors[@]} # Output: # white red yellow dark blue green black </syntaxhighlight>上面的例子中,<code>${colors[@]}</code> 扩展为整个数组,并被置换到复合赋值语句中,接着,对数组<code>colors</code>的赋值覆盖了它原来的值。 ==== 从数组中删除元素 ==== 用<code>unset</code>命令来从数组中删除一个元素:<syntaxhighlight lang="shell"> unset nums[0] echo ${nums[@]} # Output: # 1 2 </syntaxhighlight> === 运算符 === ==== 算术运算符 ==== 下表列出了常用的算术运算符,假定变量 x 为 10,变量 y 为 20: {| class="wikitable" !运算符 !说明 !举例 |- | + |加法 |<code>expr $x + $y</code> 结果为 30。 |- | - |减法 |<code>expr $x - $y</code> 结果为 -10。 |- |* |乘法 |<code>expr $x * $y</code> 结果为 200。 |- |/ |除法 |<code>expr $y / $x</code> 结果为 2。 |- |% |取余 |<code>expr $y % $x</code> 结果为 0。 |- |= |赋值 |<code>x=$y</code> 将把变量 y 的值赋给 x。 |- |== |相等。用于比较两个数字,相同则返回 true。 |<code>[ $x == $y ]</code> 返回 false。 |- |!= |不相等。用于比较两个数字,不相同则返回 true。 |<code>[ $x != $y ]</code> 返回 true。 |} '''注意:'''条件表达式要放在方括号之间,并且要有空格,例如: <code>[$x==$y]</code> 是错误的,必须写成 <code>[ $x == $y ]</code>。 ==== 关系运算符 ==== 关系运算符只支持数字,不支持字符串,除非字符串的值是数字。 下表列出了常用的关系运算符,假定变量 x 为 10,变量 y 为 20: {| class="wikitable" !运算符 !说明 !举例 |- |<code>-eq</code> |检测两个数是否相等,相等返回 true。 |<code>[ $a -eq $b ]</code>返回 false。 |- |<code>-ne</code> |检测两个数是否相等,不相等返回 true。 |<code>[ $a -ne $b ]</code> 返回 true。 |- |<code>-gt</code> |检测左边的数是否大于右边的,如果是,则返回 true。 |<code>[ $a -gt $b ]</code> 返回 false。 |- |<code>-lt</code> |检测左边的数是否小于右边的,如果是,则返回 true。 |<code>[ $a -lt $b ]</code> 返回 true。 |- |<code>-ge</code> |检测左边的数是否大于等于右边的,如果是,则返回 true。 |<code>[ $a -ge $b ]</code> 返回 false。 |- |<code>-le</code> |检测左边的数是否小于等于右边的,如果是,则返回 true。 |<code>[ $a -le $b ]</code>返回 true。 |} ==== 布尔运算符 ==== 下表列出了常用的布尔运算符,假定变量 x 为 10,变量 y 为 20: {| class="wikitable" !运算符 !说明 !举例 |- |<code>!</code> |非运算,表达式为 true 则返回 false,否则返回 true。 |<code>[ ! false ]</code> 返回 true。 |- |<code>-o</code> |或运算,有一个表达式为 true 则返回 true。 |<code>[ $a -lt 20 -o $b -gt 100 ]</code> 返回 true。 |- |<code>-a</code> |与运算,两个表达式都为 true 才返回 true。 |<code>[ $a -lt 20 -a $b -gt 100 ]</code> 返回 false。 |} ==== 逻辑运算符 ==== 以下介绍 Shell 的逻辑运算符,假定变量 x 为 10,变量 y 为 20: {| class="wikitable" !运算符 !说明 !举例 |- |<code>&&</code> |逻辑的 AND |<code>[[ ${x} -lt 100 && ${y} -gt 100 ]]</code> 返回 false |- |<code><nowiki>||</nowiki></code> |逻辑的 OR |<code><nowiki>[[ ${x} -lt 100 || ${y} -gt 100 ]]</nowiki></code> 返回 true |} ==== 字符串运算符 ==== 下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg": {| class="wikitable" !运算符 !说明 !举例 |- |<code>=</code> |检测两个字符串是否相等,相等返回 true。 |<code>[ $a = $b ]</code> 返回 false。 |- |<code>!=</code> |检测两个字符串是否相等,不相等返回 true。 |<code>[ $a != $b ]</code> 返回 true。 |- |<code>-z</code> |检测字符串长度是否为 0,为 0 返回 true。 |<code>[ -z $a ]</code> 返回 false。 |- |<code>-n</code> |检测字符串长度是否为 0,不为 0 返回 true。 |<code>[ -n $a ]</code> 返回 true。 |- |<code>str</code> |检测字符串是否为空,不为空返回 true。 |<code>[ $a ]</code> 返回 true。 |} ==== 文件测试运算符 ==== 文件测试运算符用于检测 Unix 文件的各种属性。 属性检测描述如下: {| class="wikitable" !操作符 !说明 !举例 |- | -b file |检测文件是否是块设备文件,如果是,则返回 true。 |<code>[ -b $file ]</code> 返回 false。 |- | -c file |检测文件是否是字符设备文件,如果是,则返回 true。 |<code>[ -c $file ]</code> 返回 false。 |- | -d file |检测文件是否是目录,如果是,则返回 true。 |<code>[ -d $file ]</code> 返回 false。 |- | -f file |检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 |<code>[ -f $file ]</code> 返回 true。 |- | -g file |检测文件是否设置了 SGID 位,如果是,则返回 true。 |<code>[ -g $file ]</code> 返回 false。 |- | -k file |检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 |<code>[ -k $file ]</code>返回 false。 |- | -p file |检测文件是否是有名管道,如果是,则返回 true。 |<code>[ -p $file ]</code> 返回 false。 |- | -u file |检测文件是否设置了 SUID 位,如果是,则返回 true。 |<code>[ -u $file ]</code> 返回 false。 |- | -r file |检测文件是否可读,如果是,则返回 true。 |<code>[ -r $file ]</code> 返回 true。 |- | -w file |检测文件是否可写,如果是,则返回 true。 |<code>[ -w $file ]</code> 返回 true。 |- | -x file |检测文件是否可执行,如果是,则返回 true。 |<code>[ -x $file ]</code> 返回 true。 |- | -s file |检测文件是否为空(文件大小是否大于 0),不为空返回 true。 |<code>[ -s $file ]</code> 返回 true。 |- | -e file |检测文件(包括目录)是否存在,如果是,则返回 true。 |<code>[ -e $file ]</code> 返回 true。 |} === 控制语句 === ==== 条件语句 ==== ==== if ==== <code>if</code>在使用上跟其它语言相同。如果中括号里的表达式为真,那么<code>then</code>和<code>fi</code>之间的代码会被执行。<code>fi</code>标志着条件代码块的结束。<syntaxhighlight lang="shell"> # 写成一行 if [[ 1 -eq 1 ]]; then echo "1 -eq 1 result is: true"; fi # Output: 1 -eq 1 result is: true # 写成多行 if [[ "abc" -eq "abc" ]] then echo ""abc" -eq "abc" result is: true" fi # Output: abc -eq abc result is: true </syntaxhighlight> ==== if else ==== 同样,我们可以使用<code>if..else</code>语句,例如:<syntaxhighlight lang="shell"> if [[ 2 -ne 1 ]]; then echo "true" else echo "false" fi # Output: true </syntaxhighlight> ==== if elif else ==== 有些时候,当<code>if..else</code>不能满足我们的要求。还可以使用<code>if..elif..else</code>,例如:<syntaxhighlight lang="shell"> x=10 y=20 if [[ ${x} > ${y} ]]; then echo "${x} > ${y}" elif [[ ${x} < ${y} ]]; then echo "${x} < ${y}" else echo "${x} = ${y}" fi # Output: 10 < 20 </syntaxhighlight> ==== case ==== 如果你需要面对很多情况,分别要采取不同的措施,那么使用<code>case</code>会比嵌套的<code>if</code>更有用。使用<code>case</code>来解决复杂的条件判断,例如:<syntaxhighlight lang="shell"> exec case ${oper} in "+") val=`expr ${x} + ${y}` echo "${x} + ${y} = ${val}" ;; "-") val=`expr ${x} - ${y}` echo "${x} - ${y} = ${val}" ;; "*") val=`expr ${x} \* ${y}` echo "${x} * ${y} = ${val}" ;; "/") val=`expr ${x} / ${y}` echo "${x} / ${y} = ${val}" ;; *) echo "Unknown oper!" ;; esac </syntaxhighlight> === 循环语句 === Bash 中有四种循环:<code>for</code>,<code>while</code>,<code>until</code>和<code>select</code>。 ==== for循环 ==== <syntaxhighlight lang="shell"> for arg in elem1 elem2 ... elemN do ### 语句 done </syntaxhighlight>在每次循环的过程中,<code>arg</code>依次被赋值为从<code>elem1</code>到<code>elemN</code>。这些值还可以是通配符或者大括号扩展。 我们还可以把<code>for</code>循环写在一行,但这要求<code>do</code>之前要有一个分号,例如:<syntaxhighlight lang="shell"> for i in {1..5}; do echo $i; done </syntaxhighlight>也可以像 C 语言那样使用<code>for</code>,比如:<syntaxhighlight lang="shell"> for (( i = 0; i < 10; i++ )); do echo $i done </syntaxhighlight>当我们想对一个目录下的所有文件做同样的操作时,<code>for</code>就很方便了。举个例子,如果我们想把所有的<code>.bash</code>文件移动到<code>script</code>文件夹中,我们的脚本可以这样写:<syntaxhighlight lang="shell"> DIR=/home/zp for FILE in ${DIR}/*.sh; do mv "$FILE" "${DIR}/scripts" done # 将 /home/zp 目录下所有 sh 文件拷贝到 /home/zp/scripts </syntaxhighlight> ==== while循环 ==== <code>while</code>循环检测一个条件,只要这个条件为 真,就执行一段命令。被检测的条件跟<code>if..then</code>中使用的基元并无二异。因此一个<code>while</code>循环看起来会是这样: <syntaxhighlight lang="shell"> while [[ condition ]] do ### 语句 done </syntaxhighlight> 跟<code>for</code>循环一样,如果我们把<code>do</code>和被检测的条件写到一行,那么必须要在<code>do</code>之前加一个分号。 比如下面这个例子: <syntaxhighlight lang="shell"> ### 0到9之间每个数的平方 x=0 while [[ ${x} -lt 10 ]]; do echo $((x * x)) x=$((x + 1)) done # Output: # 0 # 1 # 4 # 9 # 16 # 25 # 36 # 49 # 64 # 81 </syntaxhighlight> ==== until循环 ==== <code>until</code>循环跟<code>while</code>循环正好相反。它跟<code>while</code>一样也需要检测一个测试条件,但不同的是,只要该条件为 假 就一直执行循环: <syntaxhighlight lang="shell"> x=0 until [[ ${x} -ge 5 ]]; do echo ${x} x=`expr ${x} + 1` done # Output: # 0 # 1 # 2 # 3 # 4 </syntaxhighlight> ==== select in 循环 ==== select in 循环用来增强交互性,它可以显示出带编号的菜单,用户输入不同的编号就可以选择不同的菜单,并执行不同的功能。 select in 是 Shell 独有的一种循环,非常适合终端(Terminal)这样的交互场景,C语言、C++、Java、Python、C# 等其它编程语言中是没有的。 Shell select in 循环的用法如下: <syntaxhighlight lang="text"> select variable in value_list do statements done </syntaxhighlight> variable 表示变量,value_list 表示取值列表,in 是 Shell 中的关键字。你看,select in 和 for in 的语法是多么地相似。 我们先来看一个 select in 循环的例子: <syntaxhighlight lang="shell"> #!/bin/bash echo "What is your favourite OS?" select name in "Linux" "Windows" "Mac OS" "UNIX" "Android" do echo $name done echo "You have selected $name" </syntaxhighlight> 运行结果: <syntaxhighlight lang="text"> What is your favourite OS? 1) Linux 2) Windows 3) Mac OS 4) UNIX 5) Android #? 4↙ You have selected UNIX #? 1↙ You have selected Linux #? 9↙ You have selected #? 2↙ You have selected Windows #?^D </syntaxhighlight> <code>#?</code>用来提示用户输入菜单编号;<code>^D</code>表示按下 Ctrl+D 组合键,它的作用是结束 select in 循环。 运行到 select 语句后,取值列表 value_list 中的内容会以菜单的形式显示出来,用户输入菜单编号,就表示选中了某个值,这个值就会赋给变量 variable,然后再执行循环体中的 statements(do 和 done 之间的部分)。 每次循环时 select 都会要求用户输入菜单编号,并使用环境变量 PS3 的值作为提示符,PS3 的默认值为#?,修改 PS3 的值就可以修改提示符。 如果用户输入的菜单编号不在范围之内,例如上面我们输入的 9,那么就会给 variable 赋一个空值;如果用户输入一个空值(什么也不输入,直接回车),会重新显示一遍菜单。 注意,select 是无限循环(死循环),输入空值,或者输入的值无效,都不会结束循环,只有遇到 break 语句,或者按下 Ctrl+D 组合键才能结束循环。 完整实例 select in 通常和 case in 一起使用,在用户输入不同的编号时可以做出不同的反应。 修改上面的代码,加入 case in 语句: <syntaxhighlight lang="shell"> #!/bin/bash echo "What is your favourite OS?" select name in "Linux" "Windows" "Mac OS" "UNIX" "Android" do case $name in "Linux") echo "Linux是一个类UNIX操作系统,它开源免费,运行在各种服务器设备和嵌入式设备。" break ;; "Windows") echo "Windows是微软开发的个人电脑操作系统,它是闭源收费的。" break ;; "Mac OS") echo "Mac OS是苹果公司基于UNIX开发的一款图形界面操作系统,只能运行与苹果提供的硬件之上。" break ;; "UNIX") echo "UNIX是操作系统的开山鼻祖,现在已经逐渐退出历史舞台,只应用在特殊场合。" break ;; "Android") echo "Android是由Google开发的手机操作系统,目前已经占据了70%的市场份额。" break ;; *) echo "输入错误,请重新输入" esac done </syntaxhighlight> 用户只有输入正确的编号才会结束循环,如果输入错误,会要求重新输入。 运行结果1,输入正确选项: <syntaxhighlight lang="text"> What is your favourite OS? 1) Linux 2) Windows 3) Mac OS 4) UNIX 5) Android #? 2 Windows是微软开发的个人电脑操作系统,它是闭源收费的。 </syntaxhighlight> 运行结果2,输入错误选项: <syntaxhighlight lang="text"> What is your favourite OS? 1) Linux 2) Windows 3) Mac OS 4) UNIX 5) Android #? 7 输入错误,请重新输入 #? 4 UNIX是操作系统的开山鼻祖,现在已经逐渐退出历史舞台,只应用在特殊场合。 </syntaxhighlight> 运行结果3,输入空值: <syntaxhighlight lang="text"> What is your favourite OS? 1) Linux 2) Windows 3) Mac OS 4) UNIX 5) Android #? 1) Linux 2) Windows 3) Mac OS 4) UNIX 5) Android #? 3 Mac OS是苹果公司基于UNIX开发的一款图形界面操作系统,只能运行与苹果提供的硬件之上。 </syntaxhighlight> ==== break和continue ==== 如果想提前结束一个循环或跳过某次循环执行,可以使用 shell 的<code>break</code>和<code>continue</code>语句来实现。它们可以在任何循环中使用。 <code>break</code>语句用来提前结束当前循环。 <code>continue</code>语句用来跳过某次迭代。 <syntaxhighlight lang="shell"> # 查找 10 以内第一个能整除 2 和 3 的正整数 i=1 while [[ ${i} -lt 10 ]]; do if [[ $((i % 3)) -eq 0 ]] && [[ $((i % 2)) -eq 0 ]]; then echo ${i} break; fi i=`expr ${i} + 1` done # Output: 6 </syntaxhighlight> <syntaxhighlight lang="shell"> # 打印10以内的奇数 for (( i = 0; i < 10; i ++ )); do if [[ $((i % 2)) -eq 0 ]]; then continue; fi echo ${i} done # Output: # 1 # 3 # 5 # 7 # 9 </syntaxhighlight> === 函数 === ==== 位置参数 ==== ==== 函数处理参数 ====
返回至“
Shell new
”。
导航菜单
个人工具
登录
名字空间
页面
讨论
变体
视图
阅读
查看源代码
查看历史
更多
搜索
导航
-==扬==-
-==帆==-
-==起==-
-==航==-
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息