[Happy BASH] BASH 编程学习点点滴滴

来源:互联网 发布:网络与新媒体概论 pdf 编辑:程序博客网 时间:2024/04/30 19:50
1. 用ECHO命令,但不想要它输出行末的换行符,可以采用以下3种方法:
a) printf "xxxx"  
b) echo -n "xxxxx"
c) echo -e "xxx\c"
注意:-e选项代表启用ESCAPE字符,\c代表不输出其后的所有字符. 所以"xxxx\cyyyy"将只会输出“xxxx"。

2. 将ls命令的输出导出到一个文件中。
ls > somefile
你将会得到所有项,但是一项一行。
然而ls命令的输出结果却是所有的项是以空格分隔的。

所以输出文件如果想要得到跟ls命令一样的文本输出,可以用以下的选项ls -C > somefile.将会得到以空格分隔的目录项了。

BTW, “ls -1"将会得到每项每行的输出结果。

原因分析:
a) > 重定向操作对于程序来是透明的,就是说程序并不需要特别handle将自己的输出重定向到文件的代码。
b) 然而,ls程序的开发者却有意为之,当发现默认输出到屏幕时,它采用-C选项,当发现是重定向到输出文件时,它采用的是-1选项。

3. 将stdout/stderr 都输出到外部文件中,可以用以下写法:
a) command >& somefile
b) command &> somefile
c) command > somefile 2>&1  (老的写法)

the 2>& are a single entity, indicating that standard output (2) will be redirected (>) to a file
descriptor (&) that follows (1). The 2>& all have to appear together without spaces,
otherwise the 2 would look just like another argument, and the & actually means
something completely different when it appears by itself. (It has to do with running
the command in the background.)

4. 可以group一系列的command的输出到一个文件中:
{ pwd; cd "$subdir"; ls; } > test.txt 
注意,{ } 需要被BASH解析为command,所以需要在{后加一个空格,和在}前加一个空格。
或者用 subshell的概念,可达到相同的效果。
(pwd; cd "$subdir"; ls) > test.txt

然而上述两者存在很大的不同:
1) 用 { }时,执行的命令环境仍然是当前的shell,而用( )时,执行的命令环境是subshell。不过大部分的环境变量都相同,但是trap却有点不同。
2) 当然语法上有些不同:{ }方法必须有空格分隔,而且最后一个命令必须是以;结尾。而( )方法却不要求这些。
3) 最大的不同是cd命令: { }方法将会停止在$subdir目录,因为它影响到了当前的shell。而( )方法仍然会返回到之前的目录,因为CD命令运行subshell中。

跟这个问题有关的就是PIPE(管道)的使用:
$command1 | $command2
其实每个命令都是运行在各自独立的subshell中,以至于一下的命令就会是期待
pwd
/home/$user/test/
cat test.txt | cd ../
pwd
/home/$user/test/

5. tee 命令
将控制台输入dup一份到参数所描述的输出文件中,同时也输出一份到控制台。该命令的用途在于插入到两个用pipe连接的命令之间,DEBUG查看前面的命令是否有输出。
find / -name '*.c' -print 2>&1 | tee /tmp/all.my.sources

6. 有些命令无法接受标准输入或者输入文件,只接受参数输入,譬如rm。那么该如何将一个命令的输出作为参数传给这类的命令。可以采用命令替换的方法。如下:
rm $(find ./ -name ‘*.txt’)
$()会将换行符转为空格,所有find的输出将会以空格分隔。


7. 重定向文件命令写法的区别:
$ somecmd >my.file 2>&1
$ somecmd 2>&1 >my.file

这2个命令是有很重大的区别的:
1) 1命令是比较常规的写法,将stderr和stdout的输出结果全部重定向到文件my.file。先是STDOUT重定向到my.file,然后STDERR重定向到STDOUT。故所有输出都会进入my.file中。
2) 2命令首先将STDERR输出重定向到STDOUT中(这时将会连接屏幕输出),然后将STDOUT输出重定向到my.file,所以最后只有STDOUT的输出会进入my.file,STDERR的输出并不会进入my.file,而只会到屏幕。

8. 交换STDOUT和STERR
$ ./myscript 3>&1 1>&2 2>&3
n>&m意识说n=dup(m)。将m file descriptor dup一份到n.
所以上述命令的意思是将STDERR和STDOUT交换。
故可以将STDERR的输出通过PIPE传出去,而不是STDOUT。因为PIPE只传STDOUT的输出。
$ ./myscript 3>&1 1>stdout.logfile 2>&3- | tee -a stderr.logfile

9. Here Document碰到escape字符
grep $1 <<EOF
# name amt
pete $100
joe $200
sam $ 25
bill $ 9
EOF
$1/$2将会被解析为变量,而不是普通的字符。故需要将这些字符去除转移:
# solution
grep $1 <<\EOF
pete $100
joe $200
sam $ 25
bill $ 9
EOF

10. nohup 命令的用法
当我们想要将某一个程序运行在后台(用 &),但是发现如果我们关闭了shell之后,这个后台程序也死掉了。原因在于后台程序也是当前shell的子程序。当shell消亡时,它会发信号SIGHUP给所有它的子进程,导致所有的子进程都死亡。
可以采用nohup $command &命令来达到子进程不消亡的目的。这个nohup就是告诉子进程不要理会SIGHUP信号。

但是问题来了,就是如果子进程所依赖的SHELL消亡了,那它就没办法输出任何东西到SHELL,不然就导致CRASH。所以nohup还做了一件事情,就是智能的将输出到控制台重定向到一个当前目录下的文件nohup.out文件,当然如果在运行$command时,已经重定向到输出到另一个文件中了,那么nohup将不会帮忙做这个重定向操作。


11. 关于printf与"%b", "%s"的配合使用:
a) printf "%s\n" "hello\nworld\n"
将会输出hello\nworld\n
b) printf "%b\n" "hello\nworld\n"
将会输出
hello
world

c) printf "hello\nworld\n"
将会输出
hello
world

"%b"选项类似于echo-style escape,"-e"。会将字符串中的相关字符进行转义。

12. 如何嵌入多行注释
通过: << 'EOF_DOC'
xxxxx
xxxx
EOF_DOC


a) 加入 “:",是为了可支持 formated document
b) 加入 引号给 EOF_DOC,是为了让comment中去除所有的shell转义,譬如$var,不被解析为变量引用。


13. 设置默认的值操作符{:-}和{:=} 
FILEDIR=${1:-'/tmp/'}
equals to below code:
FILEDIR='/tmp'
if [ -n "$1" ]; then
FILEDIR="$1"
fi

a) 没有设置;b) 设置了,但是空字符串,或者另一个null变量。

相似的但有所区别的一个操作符就是{:=}。它除了实现提供默认值之外,还给:左边的变量符赋那个值。但是它不使用与$1,$2, etc.可能是因为它们的值通过外部不能修改的原因。
PATH=${HOME:='/tmp'}
比较容易的记法就是"-"是"="的一半操作。

另一个需要注意的是{=}操作符。它是在=左边的变量没有设置或者显示的UNSET的情况下,才会用右边的值进行设置。不同于上面2者的多一种情况就是左边值为EMPTY STRING时,也会赋值。

$ echo ${HOME=/tmp} # no substitution needed
/home/uid002
$ HOME="" # generally not wise
$ echo ${HOME=/tmp} # will NOT substitute

$ unset HOME # generally not wise
$ echo ${HOME=/tmp} # will substitute
/tmp
$ echo $HOME
/tmp
$

 {:?}判断:左边的变量是否为空,或者没设置。如果是的(没设置/空),那么就执行?右边的语句,并退出。如果有值,那么就取出变量,赋值给其它值。
FILEPATH=${1:? "ERROR, argument 1 is not set"}

14. 如何用数组
MYRA=(first second third home)
echo runners on ${MYRA[0]} and ${MYRA[2]}


15. ${...}可以干的事情:

inside ${ ... } Action takenname:number:number  Substring starting character, length#name Return the length of the stringname#pattern  Remove (shortest) front-anchored patternname##pattern Remove (longest) front-anchored patternname%pattern Remove (shortest) rear-anchored patternname%%pattern Remove (longest) rear-anchored patternname/pattern/string Replace first occurrencename//pattern/string Replace all occurrences