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.)
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
# 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
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
$
/home/uid002
$ HOME="" # generally not wise
$ echo ${HOME=/tmp} # will NOT substitute
$ 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 taken |
name:number:number | Substring starting character, length |
#name | Return the length of the string |
name#pattern | Remove (shortest) front-anchored pattern |
name##pattern | Remove (longest) front-anchored pattern |
name%pattern | Remove (shortest) rear-anchored pattern |
name%%pattern | Remove (longest) rear-anchored pattern |
name/pattern/string | Replace first occurrence |
name//pattern/string | Replace all occurrences |