继上篇 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
参考
(如有错误或不同的见解, 望不吝指出, 愿共同进步!)