共计 3095 个字符,预计需要花费 8 分钟才能阅读完成。
继上篇 shell 入门文章, 该篇文章会列举出我在学习 shell 的过程中, 遇到的一些疑问, 然后自己查资料以后的解答.
如何运行 shell 脚本
回顾例子:
[root@host shell]# vim start | |
[root@host shell]# cat start | |
#!/bin/bash | |
echo 'hello' | |
[root@host shell]# chmod 755 start | |
[root@host shell]# ./start | |
hello | |
[root@host shell]# |
执行时, 为什么要加 ./
?
这要从系统的 $PATH
变量说起, 当我们执行例如 ls
, pwd
等指令时, linux 并不会在整个系统翻箱倒柜搜索 ls
, pwd
程序, 而是会从 $PATH
变量定义的目录列表下查找, 如果找不到, 就会报 command not found
的错误.
因为我们的脚本不在 $PATH
变量目录列表下, 所以需要加上 ./
指示该应用程序处于当前目录下.
另外, 如果我们不想加 ./
, 可以将该目录作为系统搜寻指令的其中一个目录:
[root@host shell]# vim ~/.bash_profile | |
# 修改 .bash_profile, 添加你的脚本目录. | |
# $PATH 变量定义中, 多个目录用冒号 : 分隔 | |
export PATH="$PATH":~/shell | |
# 让 shell 重新读取配置文件 | |
[root@host shell]# source ~/.bash_profile | |
[root@host shell]# start | |
hello |
第一行 #!/bin/bash
有什么作用 ?
告诉操作系统用什么解释器执行该脚本
为什么要给文件加权限 chmod 755
?
linux 系统默认不允许一个文本文件作为程序被执行, 所以要给文件添加可执行的权限
shell 和 bash 有什么关系 ?
shell 是一类应用程序, 它接收键盘输入的命令, 然后将命令传递给操作系统去执行, 是用户与操作系统的沟通桥梁.
bash 是使用广泛的一款 shell 程序, Linux 系统的标配, 也可以使用其他 shell 程序, 比如 sh.
~/.bashrc
, ~/.bash_profile
文件有什么区别 ?
这两个文件都是 shell 脚本文件, 会在不同的时机被执行.~/.bash_profile
会在 linux 用户登录的时候被执行.~/.bashrc
在非登录时就会被执行.
另外, 一般在 ~/.bash_profile
脚本内, 会将 ~/.bashrc
内容进行执行, 比如某些服务器的 ~/.bash_profile
文件内, 会有代码:
# Get the aliases and functions | |
if [-f ~/.bashrc]; then | |
. ~/.bashrc | |
fi |
shell 命令内自带程序名字的来源有哪些 ?
- 在 shell 的配置文件中, 比如
~/.bashrc
, 内定义的$PATH
目录列表中可找到的程序 - 在 shell 配置文件内定义的 shell 函数
数据类型
回顾数组
# 初始化 | |
a[2]=100 | |
a=(2 4 'str' 4) | |
a=([0]=2 [2]='str' [4]=20) | |
# 单个赋值 | |
a[2]='s' | |
# 打印整个数组 | |
echo ${a[@]} | |
# 遍历数组 | |
for i in ${a[@]}; do | |
echo $i | |
done | |
# 数组元素个数 | |
echo ${#a[@]} | |
# 指定下标添加元素 | |
a=([0]=2 [2]='str') | |
a[3]=1 | |
a[6]=6 | |
# 删除整个数组 | |
unset a | |
# 删除数组内单个元素 | |
unset a[1] |
数组内可以放置字符串和整数的混搭吗 ?
可以, 比如
a=([1]=sun [6]=$((2+3)) )
对数组进行跨越 (不连续) 赋值, 遍历数组时, 会遍历未赋值元素吗 ?
不会
a=([1]=sun [6]=$((2+3)) ) | |
for i in ${a[*]}; do | |
echo 0 | |
echo $i | |
done | |
# 0 | |
# sun | |
# 0 | |
# 5 |
'
和 "
区别 ?
[root@host shell]# echo "$foo" | |
start | |
[root@host shell]# echo '$foo' | |
$foo |
双引号内, 会进行参数展开.
单引号内, 不进行参数展开.
什么是参数展开 ?
即 将变量名替换为具体的值, 比如
[root@host shell]# a="-l" | |
[root@host shell]# ls $a | |
total 4 | |
-rwxr-xr-x 1 root root 26 Oct 19 07:29 start |
ls $a
参数展开以后会是 ls -l
变量, 表达式, 控制流
为什么要给变量加花括号 {}
?
a=1 | |
echo ${a} # 1 | |
echo $a # 1 |
以上, a
变量加不加花括号都没关系, 但是一些情况下, 需要给变量加上花括号, 为了更清晰的指出我们操作的是什么变量
例如我想修改文件名, 给文件名末尾加一个 “1”
[root@host shell]# foo=start | |
[root@host shell]# mv $foo $foo1 | |
mv: missing destination file operand after‘start’Try 'mv --help' for more information. | |
[root@host shell]# mv $foo ${foo}1 | |
[root@host shell]# ll | |
total 4 | |
-rwxr-xr-x 1 root root 26 Oct 19 07:29 start1 |
有哪些 $
开头的 shell 自带变量 (待完善) ?
$? # 上一次的退出状态 | |
$REPLY # 当使用 read 命令, 且 read 没带变量名, 则 $REPLY 包含所有输入 |
$(())
与 (())
区别 ?
复合命令 (())
, 用做算术运算, 用在条件判断中, 比如 if
的条件判断.
而 $(())
用作算术展开, 用作整数赋值, 比如 foo=$((1))
()
与 (())
区别 ?
()
用于创建 子 shell, 应该与 {}
一起讲(())
用于算术表达式求值, 可用在条件判断中
()
与 {}
区别 ?
二者语法为
(list) # 子 shell | |
# eg | |
(ls -l; echo 'hello') > output.txt | |
{list;} # 组合命令 | |
# eg | |
{ls -l; echo 'hello';} > output2.txt |
二者都可以内置一个命令列表, 运行以后会执行该命令列表.
- 语法上的不同:
在组合命令中, {
与 list 之间需要一个空格, 而 {list;}
的 list 最后需要带上分号 ;
, 而 (list)
没有这些限制
- 功能上的不同:
组合命令会在当前环境执行该命令列表, 产生的对环境变量的变动会保留在当前执行环境.
而子 shell 则会新建一个执行环境, 在新的执行环境内执行命令列表, 所以当子 shell 内命令列表执行完以后, 子 shell 会被销毁, 子 shell 内的环境变量也会相应的被销毁.
[]
与 [[]]
区别 ?
[]
用于控制流中的条件判断.[[]]
拥有 []
的能力, 且增加了正则表达式的能力.
$(())
与 (())
结合使用 ?
a=0 | |
if (($(( $a + 1)) == 1 )); then | |
echo 'hello' | |
fi |
解析:
- if 跟着的
(())
是复合命令, 用作条件判断 - 内部的
$(($a + 1))
是算术展开, 用作算术求值 -
$a + 1
是一个表达式
其他
如何在 vim 编辑器里运行 linux 命令 ?
Esc | |
:!linux_command |
注意: 如果要运行正在编辑的 shell 脚本, 记得先进行保存: :w
参考
http://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameter-Expansion
http://billie66.github.io/TLCL/book/index.html
https://www.gnu.org/software/bash/manual/html_node/Command-Grouping.html#Command-Grouping
(如有错误或不同的见解, 望不吝指出, 愿共同进步!)