成与坚持,败于止步
文件系统
cd
cd, 修改目录命令, 在脚本中用的最多的时候就是当命令需要在指定目录下运行时, 需要用它来修改当前工作目录.
这里只是提一下比较特殊的情况,也许你不是很常用这些
cd - 将会把工作目录修改至$OLDPWD, 也就是之前的工作目录.
root@haitao-VirtualBox:~# cd mysrc/ root@haitao-VirtualBox:~/mysrc# cd - /root root@haitao-VirtualBox:~# cd mysrc/ root@haitao-VirtualBox:~/mysrc# cd /root/myshare/ root@haitao-VirtualBox:~/myshare# cd - /root/mysrc root@haitao-VirtualBox:~/mysrc#当我们使用两个"/"来作为cd命令的参数时, 结果却出乎我们的意料,当然单个“/”是没有问题的
root@haitao-VirtualBox:~/mysrc# cd / root@haitao-VirtualBox:/# cd root@haitao-VirtualBox:~# cd // root@haitao-VirtualBox://# pwd // root@haitao-VirtualBox://#
pwd
打印出当前的工作目录. 这将给出用户(或脚本)的当前工作目录 , 使用这个命令的结果和从内建变量$PWD中所读取的值是相同的.
pushd, popd, dirs
这几个命令可以使得工作目录书签化, 就是可以按顺序向前或向后移动工作目录. 压栈的动作可以保存工作目录列表. 选项可以允许对目录栈做不同的操作.
pushd dir-name把路径dir-name压入目录栈, 同时修改当前目录到dir-name.
popd将目录栈最上边的目录弹出, 同时将当前目录修改为刚弹出来的那个目录.
dirs列出所有目录栈的内容 (与$DIRSTACK变量相比较). 一个成功的pushd或者popd将会自动调用dirs命令.
对于那些并没有对当前目录做硬编码, 并且需要对当前工作目录做灵活修改的脚本来说, 使用这些命令是再好不过了. 注意内建$DIRSTACK数组变量, 这个变量可以在脚本中进行访问, 并且它们保存了目录栈的内容.
root@ubuntu:~/resource/shell-study/0614-2013# pushd `pwd` ~/resource/shell-study/0614-2013 ~/resource/shell-study/0614-2013 root@ubuntu:~/resource/shell-study/0614-2013# cd root@ubuntu:~# popd ~/resource/shell-study/0614-2013 root@ubuntu:~/resource/shell-study/0614-2013# dirs ~/resource/shell-study/0614-2013 root@ubuntu:~/resource/shell-study/0614-2013#
看一个修改当前工作目录的实例
#!/bin/bash dir1=/usr/local dir2=/var/spool pushd $dir1 # 将自动运行一个 'dirs' (把目录栈的内容列到stdout上). echo "Now in directory `pwd`." # 使用后置引用的 'pwd'. # 现在对'dir1'做一些操作. pushd $dir2 echo "Now in directory `pwd`." # 现在对'dir2'做一些操作. echo "The top entry in the DIRSTACK array is $DIRSTACK." popd echo "Now back in directory `pwd`." # 现在, 对'dir1'做更多的操作. popd echo "Now back in original working directory `pwd`." exit 0结果:
root@ubuntu:~/resource/shell-study/0615-2013# chmod +x test1.sh root@ubuntu:~/resource/shell-study/0615-2013# ./test1.sh /usr/local ~/resource/shell-study/0615-2013 Now in directory /usr/local. /var/spool /usr/local ~/resource/shell-study/0615-2013 Now in directory /var/spool. The top entry in the DIRSTACK array is /var/spool. /usr/local ~/resource/shell-study/0615-2013 Now back in directory /usr/local. ~/resource/shell-study/0615-2013 Now back in original working directory /root/resource/shell-study/0615-2013. root@ubuntu:~/resource/shell-study/0615-2013#没什么难的,静下心来分析一下就清楚了
变量
let
let命令将执行变量的算术操作. 在许多情况下, 它被看作是复杂的expr命令的一个简化版本.
一个使用"let"命令来做算术运算的实例
#!/bin/bash echo let a=11 # 与 'a=11' 相同 let a=a+5 # 等价于 let "a = a + 5" # (双引号和空格是这句话更具可读性.) echo "11 + 5 = $a" # 16 let "a <<= 3" # 等价于 let "a = a << 3" echo "\"\$a\" (=16) left-shifted 3 places = $a" # 128 let "a /= 4" # 等价于 let "a = a / 4" echo "128 / 4 = $a" # 32 let "a -= 5" # 等价于 let "a = a - 5" echo "32 - 5 = $a" # 27 let "a *= 10" # 等价于 let "a = a * 10" echo "27 * 10 = $a" # 270 let "a %= 8" # 等价于 let "a = a % 8" echo "270 modulo 8 = $a (270 / 8 = 33, remainder $a)" # 6 echo exit 0结果:
root@ubuntu:~/resource/shell-study/0615-2013# chmod +x test2.sh root@ubuntu:~/resource/shell-study/0615-2013# ./test2.sh 11 + 5 = 16 "$a" (=16) left-shifted 3 places = 128 128 / 4 = 32 32 - 5 = 27 27 * 10 = 270 270 modulo 8 = 6 (270 / 8 = 33, remainder 6) root@ubuntu:~/resource/shell-study/0615-2013#eval
eval arg1 [arg2] ... [argN]
将表达式中的参数, 或者表达式列表, 组合起来, 然后评价它们, 任何被包含在表达示中的变量都将被扩展. 结果将会被转化到命令中. 如果你想从命令行中或者是从脚本中产生代码, 那么这个命令就非常有用了.
root@ubuntu:~/resource/shell-study/0615-2013# process=xterm root@ubuntu:~/resource/shell-study/0615-2013# show_process="eval ps ax | grep $process" root@ubuntu:~/resource/shell-study/0615-2013# $show_process 30030 pts/0 S+ 0:00 grep --color=auto xterm
一个展示eval命令的效果的实例
#!/bin/bash y=`eval ls -l` # 与 y=`ls -l` 很相似 echo $y #+ 但是换行符将会被删除, 因为"echo"的变量未被""引用. echo echo "$y" # 用""将变量引用起来, 换行符就不会被空格替换了. echo; echo y=`eval df` # 与 y=`df` 很相似 echo $y #+ 换行符又被空格替换了. # 当没有LF(换行符)出现时, 如果使用"awk"这样的工具来分析输出的结果, #+ 应该能更容易一些. echo echo "===========================================================" echo # 现在,来看一下怎么用"eval"命令来"扩展"一个变量 . . . for i in 1 2 3 4 5; do eval value=$i # value=$i 具有相同的效果, 在这里并不是非要使用"eval"不可. # 一个缺乏特殊含义的变量将被评价为自身 -- 也就是说, #+ 这个变量除了能够被扩展成自身所表示的字符外, 不能被扩展成任何其他的含义. echo $value done echo echo "---" echo for i in ls df; do value=eval $i # value=$i 在这里就与上边这句有了本质上的区别. # "eval" 将会评价命令 "ls" 和 "df" . . . # 术语 "ls" 和 "df" 就具有特殊含义, #+ 因为它们被解释成命令, #+ 而不是字符串本身. echo $value done exit 0结果:
root@ubuntu:~/resource/shell-study/0615-2013# df Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda1 19737268 7480724 11253948 40% / none 508764 276 508488 1% /dev none 512996 12 512984 1% /dev/shm none 512996 120 512876 1% /var/run none 512996 0 512996 0% /var/lock none 512996 0 512996 0% /lib/init/rw root@ubuntu:~/resource/shell-study/0615-2013# chmod +x test3.sh root@ubuntu:~/resource/shell-study/0615-2013# ./test3.sh total 12 -rwxr-xr-x 1 root root 508 2013-06-14 23:08 test1.sh -rwxr-xr-x 1 root root 693 2013-06-14 23:13 test2.sh -rwxr-xr-x 1 root root 1262 2013-06-14 23:24 test3.sh total 12 -rwxr-xr-x 1 root root 508 2013-06-14 23:08 test1.sh -rwxr-xr-x 1 root root 693 2013-06-14 23:13 test2.sh -rwxr-xr-x 1 root root 1262 2013-06-14 23:24 test3.sh Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda1 19737268 7480736 11253936 40% / none 508764 276 508488 1% /dev none 512996 12 512984 1% /dev/shm none 512996 120 512876 1% /var/run none 512996 0 512996 0% /var/lock none 512996 0 512996 0% /lib/init/rw =========================================================== 1 2 3 4 5 --- test1.sh test2.sh test3.sh 5 Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda1 19737268 7480736 11253936 40% / none 508764 276 508488 1% /dev none 512996 12 512984 1% /dev/shm none 512996 120 512876 1% /var/run none 512996 0 512996 0% /var/lock none 512996 0 512996 0% /lib/init/rw 5 root@ubuntu:~/resource/shell-study/0615-2013#强制登出(log-off)实例
#!/bin/bash # 结束ppp进程来强制登出log-off. # 本脚本应该以root用户的身份来运行. killppp="eval kill -9 `ps ax | awk '/ppp/ { print $1 }'`" # -------- ppp的进程ID ------- $killppp # 这个变量现在成为了一个命令. # 下边的命令必须以root用户的身份来运行. chmod 666 /dev/ttyS3 # 因为在ppp上执行一个SIGKILL将会修改串口的权限, #+ 我们把权限恢复到之前的状态. rm /var/lock/LCK..ttyS3 # 删除串口琐文件. exit 0eval命令是有风险的, 如果你有更合适的方法来实现功能的话, 尽量避免使用它. eval $COMMANDS将会执行命令COMMANDS的内容, 如果命令中包含有rm -rf *这样的东西, 可能就不是你想要的了. 当你运行一个包含有eval命令的陌生人所编写的代码片段的时候, 这是一件很危险的事情.
set
set命令用来修改内部脚本变量的值. 它的一个作用就是触发选项标志位来帮助决定脚本的行为. 另一个作用是以一个命令的结果(set `command`)来重新设置脚本的位置参数. 脚本将会从命令的输出中重新分析出位置参数.
一个使用set命令来改变脚本的位置参数的实例
#!/bin/bash # 使用3个命令行参数来调用这个脚本, # 比如, "./test one two three". echo echo "Positional parameters before set \`uname -a\` :" echo "Command-line argument #1 = $1" echo "Command-line argument #2 = $2" echo "Command-line argument #3 = $3" set `uname -a` # 把`uname -a`的命令输出设置 # 为新的位置参数. echo $_ # unknown(译者注: 这要看你的uname -a输出了, #这句打印出的就是输出的最后一个单词.) # 在脚本中设置标志. echo "Positional parameters after set \`uname -a\` :" # $1, $2, $3, 等等. 这些位置参数将被重新初始化为`uname -a`的结果 echo "Field #1 of 'uname -a' = $1" echo "Field #2 of 'uname -a' = $2" echo "Field #3 of 'uname -a' = $3" echo --- echo $_ # --- echo exit 0结果:
root@ubuntu:~/resource/shell-study/0615-2013# uname -a Linux ubuntu 2.6.32-21-generic #32-Ubuntu SMP Fri Apr 16 08:10:02 UTC 2010 i686 GNU/Linux root@ubuntu:~/resource/shell-study/0615-2013# ./test5.sh Positional parameters before set `uname -a` : Command-line argument #1 = Command-line argument #2 = Command-line argument #3 = GNU/Linux Positional parameters after set `uname -a` : Field #1 of 'uname -a' = Linux Field #2 of 'uname -a' = ubuntu Field #3 of 'uname -a' = 2.6.32-21-generic --- --- root@ubuntu:~/resource/shell-study/0615-2013#
root@ubuntu:~/resource/shell-study/0615-2013# ./test5.sh one two three Positional parameters before set `uname -a` : Command-line argument #1 = one Command-line argument #2 = two Command-line argument #3 = three GNU/Linux Positional parameters after set `uname -a` : Field #1 of 'uname -a' = Linux Field #2 of 'uname -a' = ubuntu Field #3 of 'uname -a' = 2.6.32-21-generic --- --- root@ubuntu:~/resource/shell-study/0615-2013#一个反转位置参数的实例
#!/bin/bash set a\ b c d\ e; # ^ ^ 转义的空格 # ^ ^ 未转义的空格 echo "old IFS=$IFS" OIFS=$IFS; IFS=:; # ^ 保存旧的IFS, 然后设置新的IFS. echo "new IFS=$IFS" echo until [ $# -eq 0 ] do # 步进位置参数. echo "### k0 = "$k"" # 步进之前 k=$1:$k; # 将每个位置参数都附加在循环变量的后边. # ^ echo "### k = "$k"" # 步进之后 echo shift; done set $k # 设置一个新的位置参数. echo - echo $# # 察看位置参数的个数. echo - echo for i # 省略 "in list" 结构, #+ 为位置参数设置变量 -- i --. do echo $i # 显示新的位置参数. done IFS=$OIFS # 恢复 IFS. exit 0结果:
root@ubuntu:~/resource/shell-study/0615-2013# chmod +x test6.sh root@ubuntu:~/resource/shell-study/0615-2013# ./test6.sh old IFS= new IFS=: ### k0 = ### k = a b ### k0 = a b ### k = c a b ### k0 = c a b ### k = d e c a b - 3 - d e c a b root@ubuntu:~/resource/shell-study/0615-2013#不使用任何选项或参数来调用set命令的话, 将会列出所有的环境变量和其他所有的已经初始化过的变量
root@ubuntu:~/resource/shell-study/0615-2013# set BASH=/bin/bash BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath BASH_ALIASES=() BASH_ARGC=() BASH_ARGV=() BASH_CMDS=() BASH_LINENO=() BASH_SOURCE=() BASH_VERSINFO=([0]="4" [1]="1" [2]="5" [3]="1" [4]="release" [5]="i486-pc-linux-gnu") BASH_VERSION='4.1.5(1)-release' CLASSPATH=.:/usr/lib/jvm/java/jdk1.7.0_13/lib COLORTERM=gnome-terminal COLUMNS=85 DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-NifSM3iDlO,guid=9ab993acd7e0b2bbecd0340551821d2e DEFAULTS_PATH=/usr/share/gconf/gnome.default.path DESKTOP_SESSION=gnome DIRSTACK=() DISPLAY=:0.0 EUID=0 GDMSESSION=gnome GDM_KEYBOARD_LAYOUT=us GDM_LANG=en_US.UTF-8 GNOME_DESKTOP_SESSION_ID=this-is-deprecated GNOME_KEYRING_CONTROL=/tmp/keyring-0pB4Zz GNOME_KEYRING_PID=1726 GROUPS=() GTK_MODULES=canberra-gtk-module HISTCONTROL=ignoredups:ignorespace HISTFILE=/root/.bash_history HISTFILESIZE=2000 HISTSIZE=1000 HOME=/root HOSTNAME=ubuntu HOSTTYPE=i486 IFS=$' \t\n' JAVA_HOME=/usr/lib/jvm/java/jdk1.7.0_13 LANG=en_US.UTF-8 LESSCLOSE='/usr/bin/lesspipe %s %s' LESSOPEN='| /usr/bin/lesspipe %s' LINES=20 LOGNAME=root LS_COLORS='rs=0:di=01;34:ln=01;36:hl=44;37:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:' MACHTYPE=i486-pc-linux-gnu MAILCHECK=60 MANDATORY_PATH=/usr/share/gconf/gnome.mandatory.path OLDPWD=/root/resource/shell-study OPTERR=1 OPTIND=1 ORBIT_SOCKETDIR=/tmp/orbit-root OSTYPE=linux-gnu PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/java/jdk1.7.0_13/bin:/opt/FriendlyARM/toolschain/4.4.3/bin PIPESTATUS=([0]="0") PPID=2090 PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' PS2='> ' PS4='+ ' PWD=/root/resource/shell-study/0615-2013 SESSION_MANAGER=local/ubuntu:@/tmp/.ICE-unix/1744,unix/ubuntu:/tmp/.ICE-unix/1744 SHELL=/bin/bash SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor SHLVL=1 SPEECHD_PORT=6560 SSH_AGENT_PID=1779 SSH_AUTH_SOCK=/tmp/keyring-0pB4Zz/ssh TERM=xterm UID=0 USER=root USERNAME=root WINDOWID=59004342 XAUTHORITY=/var/run/gdm/auth-for-root-cUTmoG/database XDG_CONFIG_DIRS=/etc/xdg/xdg-gnome:/etc/xdg XDG_DATA_DIRS=/usr/share/gnome:/usr/local/share/:/usr/share/ XDG_SESSION_COOKIE=e2701cc9fa08772c6d472e6450b8b925-1367481646.513094-1041457640 _=three process=xterm show_process='eval ps ax | grep xterm' command_not_found_handle () { if [ -x /usr/lib/command-not-found ]; then /usr/bin/python /usr/lib/command-not-found -- $1; return $?; else if [ -x /usr/share/command-not-found ]; then /usr/bin/python /usr/share/command-not-found -- $1; return $?; else return 127; fi; fi } root@ubuntu:~/resource/shell-study/0615-2013#如果使用参数--来调用set命令的话, 将会明确的分配位置参数. 如果--选项后边没有跟变量名的话, 那么结果就使得所有位置参数都被unsets了.
一个重新分配位置参数的实例
#!/bin/bash variable="one two three four five" set -- $variable # 将位置参数的内容设为变量"$variable"的内容. first_param=$1 second_param=$2 shift; shift # 将最前面的两个位置参数移除. remaining_params="$*" echo echo "first parameter = $first_param" # one echo "second parameter = $second_param" # two echo "remaining parameters = $remaining_params" # three four five echo; echo # 再来一次. set -- $variable first_param=$1 second_param=$2 echo "first parameter = $first_param" # one echo "second parameter = $second_param" # two # ====================================================== set -- # 如果没指定变量,那么将会unset所有的位置参数. first_param=$1 second_param=$2 echo "first parameter = $first_param" # (null value) echo "second parameter = $second_param" # (null value) exit 0结果:
root@ubuntu:~/resource/shell-study/0615-2013# chmod +x test7.sh root@ubuntu:~/resource/shell-study/0615-2013# ./test7.sh first parameter = one second parameter = two remaining parameters = three four five first parameter = one second parameter = two first parameter = second parameter = root@ubuntu:~/resource/shell-study/0615-2013#
unset
unset命令用来删除一个shell变量, 这个命令的效果就是把这个变量设为null. 注意: 这个命令对位置参数无效.bash$ unset PATH bash$ echo $PATH bash$"Unset"一个变量的实例
#!/bin/bash # unset.sh: Unset 一个变量. variable=hello # 初始化. echo "variable = $variable" unset variable # Unset. # 与 variable= 效果相同. echo "(unset) variable = $variable" # $variable 设为 null. exit 0结果:
root@ubuntu:~/resource/shell-study/0615-2013# chmod +x test8.sh root@ubuntu:~/resource/shell-study/0615-2013# ./test8.sh variable = hello (unset) variable = root@ubuntu:~/resource/shell-study/0615-2013#
export
export命令将会使得被export的变量在所运行脚本(或shell)的所有子进程中都可用. 不幸的是, 没有办法将变量export到父进程中, 这里所指的父进程就是调用这个脚本的脚本或shell. 关于export命令的一个重要的用法就是使用在启动文件中, 启动文件用来初始化和设置环境变量, 这样, 用户进程才能够访问环境变量.
declare, typeset
declare和typeset命令被用来指定或限制变量的属性.
readonly
与declare -r作用相同, 设置变量的只读属性, 或者可以认为这个变量就是一个常量. 设置了这种属性之后, 如果你还要修改它, 那么将会得到一个错误信息. 这种情况与C语言中的const常量类型是相同的.
getopts
可以说这个命令是分析传递到脚本中命令行参数的最强力的工具. 这个命令与外部命令getopt, 还有C语言中的库函数getopt 的作用是相同的. 它允许传递和连接多个选项到脚本中, 并且能够分配多个参数到脚本中(比如: scriptname -abc -e /usr/local).
getopts结构使用两个隐含变量. $OPTIND是参数指针(选项索引) 和$OPTARG(选项参数)(可选的)可以在选项后边附加一个参数. 在声明标签中, 选项名后边的冒号用来提示这个选项名已经分配了一个参数.
getopts结构通常都组成一组放在一个while循环中, 循环过程中每次处理一个选项和参数, 然后增加隐含变量$OPTIND的值, 再进行下一次的处理.
1、通过命令行传递到脚本中的参数前边必须加上一个减号(-). -是一个前缀, 这样getopts命令把这个参数看作为一个选项. 事实上, getopts不会处理不带-前缀的参数, 如果第一个参数就没有-, 那么将会结束选项的处理.
2、getopts的while循环模板与标准的while循环模板有些不同, 没有标准循环中的中括号[]判断条件.
3、getopts结构将会取代外部命令getopt.
先到这里了,O(∩_∩)O~
我的专栏地址:http://blog.csdn.net/column/details/shell-daily-study.html
待续。。。。