[Happy BASH] BASH 編程學習點點滴滴

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 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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章