Bash 基础学习笔记

来源:互联网 发布:iphone5怎么开3g网络 编辑:程序博客网 时间:2024/06/06 09:23

GNU/Linux支持多种版本的shell. 但默认的是bash. /etc/shells文件列出了本机linux系统支持的shell类型. /etc/passwd中列出了用户默认的登录shell.
从当前shell转换到另一种shell: 直接在命令行输入对应的shell程序名.如:
$ sh
sh-3.00$
提示符变了, 要退回到之前的bash, 可输入exit或使用C-d组合键.
bash的特色


1, 命令行参数: sh只能传送单字符参数(可通过内置的set命令配置), bash还可以传送字符串参数.
2, 启动配置文件: bash启动时, 依次读取启动文件, 这样可以在bash启动时完成一些默认的配置工作. (关于bash配置文件, 后面再讨论).
3, bash是交互性shell.
4, 条件表达式.
5, shell算术.
6, 别名.
7, 数组
8, 目录栈.
9, 受限版的bash: rbash.
bash命令的执行
bash能够识别要执行内容的类型: 是系统中的可执行程序, 还是bash的内置命令, 或者是一个bash脚本? 根据这些类型, bash的执行方式有所不同:
1, 可执行程序: 遵循fork-exec形式, 它fork出一个子bash进程, 父bash和子bash仅进程号不同. 注意这种情况下, 父进程等待子进程执行, 子bash执行完毕退出后, 父bash重新执行. 程序对子bash的环境做出的更改不会影响父bash.
2, bash内嵌命令: bash直接执行命令, 不新生成一个进程.
3, bash脚本: 分两种情况:
(1) 如果直接执行脚本, 比如: $ ./foo.sh , 此情况与执行可执行程序相同, 生成的子bash进程一次从脚本读取一行命令来执行, 如同用户从键盘输入命令.
(2) 如果执行 $ source ./foo.sh, 这相当于执行bash的内嵌命令, 也可以起到执行脚本命令的作用, 但不生成新的bash. 所以如果需要在脚本中更改bash环境变量的话, 要用source命令! 直接运行脚本只能更改fork出的子bash的环境变量, 运行结束后, 子bash退出, 父bash的环境变量不受影响.
编写bash脚本
1, 推荐使用能够显示bash语法高亮的编辑器, 比如emacs, gedit, vim...
2, 自己编写的脚本怎样命名, 放在什么地方?
命名: 为了避免自己写的脚本与系统命令重名, 建议shell脚本以.sh结尾. 但自己写的脚本还是可能与系统自带的脚本重名, 建议命名前通过$ which scriptname.sh (或者whereis, locate)来查看.
位置: 可以将自己写的脚本放在一个合适的目录中, 比如~/script.

Unix/Linux不利用文件扩展名来判断文件类型. 要想知道文件类型, 可使用file命令.

3, 如何执行脚本?
(1) 脚本可以像命令一样被执行:
$ /bin/bash file.sh (不需要file.sh的可执行权限)
如果你懒得输入/bin/bash, 可以采取下面的两种方法:
如果脚本被集中放置在~/script目录, 可以将该目录添加到PATH中再直接调用
$ export PATH="$PATH:~/script"
由于脚本所在的目录在PATH环境变量中, 所以可直接运行: $ file.sh (需要file.sh有可执行权限)
如果想执行当前目录的脚本, 可以运行$ ./scriptname.sh  (需要file.sh有可执行权限)
方法(1)使bash新生成一个子bash来执行, 在此情况下, 脚本对环境变量的更改只对子bash有效.并且在执行脚本文件之前必须更改权限(指明shell路径时不用), 让脚本具有相应的执行权限.
(2) 可使用source命令来直接执行脚本(可用'.'来代替source). 它与上面的方法有两点区别:
1, 脚本文件不需要执行权限.
2, 就在当前bash中执行, bash不会新fork一个子bash来执行它, 所以脚本对环境变量的更改会影响到当前bash.

推荐使用./file.sh在当前目录执行脚本, 这样可以避免误调系统其他位置的重名脚本. 如果需要更改当前shell的环境变量, 则使用source命令. 不推荐修改环境变量: 这会造成系统的安全隐患.

当你确认脚本运行无误, 而且需要经常执行它时, 可将它copy到合适的系统执行目录, 比如/usr/bin, /usr/local/bin 或者~/bin(需修改PATH)中. 然后向调用命令一样执行它.
脚本结构


脚本开头第一行指定运行脚本的shell, 一般指定为bash:
#!/bin/bash

bash脚本中的注释以'#'开头, #之后到行尾的内容为注释, 在执行时会被bash忽略. (脚本中不能再在同一行的注释之后添加命令, #之后到行尾的内容都会被bash忽略!)  但脚本开头的#!是个例外!

在脚本结尾的最后一行, 一般包含一个 "exit 0" 语句(0表示执行成功). 它返回一个值. 注意: 在交互式bash中, 这条命令没什么用处. 当它所在的脚本被被的脚本调用时, 就能确定被调用的脚本是否正确执行了. 你的脚本在将来可能被别的脚本所调用, 所以最好在脚本末尾包含这条语句. 这也是编写可重用脚本的一个好习惯.
调试脚本


调试整个脚本
最通用的方法是新调用一个bash, 以调试选项"-x"来执行脚本: $ bash -x scriptname.sh
这种情况下, 新bash在显示每个语句生成的结果之前打印出该语句(以+开头), 这样易于我们对比语句和执行结果.
调试脚本的部分内容
只需在脚本中你想调试的语句之前添加: set -x, 然后在结尾添加: set +x. 可以把这两条语句当作"调试开关", 在脚本中多次调用.
调试选项归纳如下:
Short notation    Long notation    Result
set -f    set -o noglob    Disable file name generation using metacharacters (globbing).
set -v    set -o verbose    Prints shell input lines as they are read.
set -x    set -o xtrace    Print command traces before executing command.
注意, -为打开启用调试,+为关闭调试,这容易混淆.
这些选项不光可以添加到脚本文件中, 还可以直接在命令行中指定.
e.g:
$ set -x
$ ls
看看结果吧 :)
bash环境
启动配置文件的读取
首先要理解: 交互式bash和非交互式bash(interactive& non-interactive)
交互式shell: 用户输入命令给shell执行, shell将执行的结果通过输出反馈给用户.
非交互式shell: 命令(脚本)在后台执行, 执行过程中不读取用户输入, 也不反馈执行信息.(执行完毕后可能会显示一些信息).

如何判断某个shell是不是交互式的呢? 可以运行 $ echo &-, 若输出中还有小写字母'i', 则是交互式shell. 一般而言, terminal或console都是交互式shell, 而shell脚本在执行时执行它的shell就是非交互式的.

交互式bash还有两种调用方式: login和non-login.
login: 我们在文本模式下登录console时, bash提示输入用户名和密码, 此时的bash就是login的.
non-login: 在图形模式下, 打开一个 terminal, 不需要输入用户明或密码, 此时调用的bash就是non-login的.
根据login和non-login的区别, bash在启动时读取不同的配置文件:
login:
1, 读取/etc/profile: 它是所有用户, 所有shell的启动配置文件. /etc/profile还会读取/etc/bash.bashrc, 它是所有用户的bash启动配置文件.
2, 读取~/.bash_profile, 若它不存在, 则读取~/.bash_login 同样, 若前两者不存在, 读取~/.profile.
3, 在logout时读取~/.bash_logout
non-login:
读取~/.bashrc.

可以自行在上述的配置文件的末尾添加echo语句, 这样在console中登录或者打开一个终端时就能显示配置文件的读取信息. 上面的总结基于Ubuntu, 各发行版可能情况不同.

non-interactive:
读取的文件由BASH_ENV定义. 这些文件要用全路径, 因为无法用PATH变量来搜寻这些文件.
bash的初始化文件


一, 针对整个系统所有用户的login配置文件.
1, 针对整个系统的所有用户, 所有shell的配置文件  /etc/profile
# System wide environment and startup programs, for login setup
注意: 该配置文件被交互式login shell读取, 以bash为例, 在图形模式下打开terminal时是交互式non-login的, 所以不会读取/etc/profile: 运行 $ bash, 不会读取/etc/profile. 但如果以 $ bash --login, 则会读取.
在字符界面下, 最初登录时会读取/etc/profile. 登录后的情形等同于图形界面的terminal.
2, 针对整个系统所有用户, bash的配置文件 /etc/bash.bashrc
它一般会被/etc/profile读取以配置bash环境.
二, 针对单个用户的login配置文件
这些配置文件默认位于用户的home目录, 以.开头, 是隐藏文件. 如果它们不存在, 可以创建它们.
1, ~/.bash_profile
This is the preferred configuration file for configuring user environments individually. In this file, users can add extra configuration options or change default settings.
与/etc/profile相同, ~/.bash_profile在交互式, login情况下被读取.
如果~/.bash_profile不存在, 则读取~/.bash_login, 若~/.bash_login也不存在, 则读取~/.profile.
三, 针对单个用户的login-out配置文件
在logout时候, bash读取~/.bash_logout文件.
四, 针对单个用户的non-login配置文件
~/.bashrc
在图形模式下, non-login bash更为广泛地存在: 打开一个terminal一般不会读取/etc/profile或~/.bash_profile文件, 因为图形模式下打开终端时是non-login的. 这种情况下通过~/.bashrc来配置.
~/.bashrc是否会被读取的情况等同于/etc/profile和~/.bash_profile.

这样, 我们就知道在定制bash环境时, 如何针对自己的需要修改这些配置文件了:
login情形下, 针对所有用户的定制: /etc/bash.bashrc;  针对单个单个用户的定制: 修改~/.bash_profile
non-login情形下: 针对所有用户的定制: /etc/bash.bashrc; 针对单个用户的定制:  修改~/.bashrc
注意: /etc/bash.bashrc会被login或non-login的bash读取!

对这出配置文件进行修改后, 可以重登录, 或者新开一个bash, 或者使用source命令来使它们生效.

有时候可能记不清到底是哪些配置文件被读取, 可在上述的文件末尾添加一条echo语句, 显示它是否被调用. 然后打开一个terminal或者进入console看看, 就知道哪些配置文件被调用, 以及它们的调用顺序.

原创粉丝点击