簡(jiǎn)介
我之前的一篇文章比我預(yù)想的更受歡迎,因此我想再寫(xiě)一篇文章來(lái)介紹一些不太知名的bash功能
正如之前所言,由于我覺(jué)得bash是一種要經(jīng)常使用(且需理解)的技術(shù),所以我在研究bash時(shí)寫(xiě)了一本書(shū)。雖然許多人并不熟悉bash,但我覺(jué)得他們也認(rèn)為非常重要便足夠令人欣喜。
1)^x^y^
我總在使用的一個(gè)小技巧。
從來(lái)沒(méi)有輸入過(guò)類(lèi)似的命令?
$ grp somestring somefile-bash: grp: command not found
哎,這個(gè)命令敲錯(cuò)了,所以你要敲“↑”,然后敲”←“直到”p“,然后輸入”e"再執(zhí)行。
或者這樣輸入:
$ ^rp^rep^grep 'somestring' somefile$
你可能需要注意的一個(gè)細(xì)節(jié)是:
$ grp rp somefile$ ^rp^rep^$ grep rp somefile
如果你想搜索“rep”,那你就要深入研究man page,學(xué)會(huì)使用這個(gè)更強(qiáng)大的命令:
$ grp rp somefile$ !!:gs/rp/repgrep rep somefile$
我不會(huì)在這里解釋這個(gè)用法。。。
2)pushd/popd
這個(gè)在腳本中非常好用,特別是在循環(huán)中
如下所示,假設(shè)你正在寫(xiě)一個(gè)進(jìn)入退出文件夾的for循環(huán):
for d1 in $(ls -d */)do # Store original working directory. original_wd="$(pwd)" cd "$d1" for d2 in $(ls -d */) do pushd "$d2" # Do something popd done # Return to original working directory cd "${original_wd}"done
你可以像這樣使用pushd棧來(lái)重寫(xiě)上方代碼:
for d1 in $(ls -d *)do pushd "$d1" for d2 in $(ls -d */) do pushd "$d2" # Do something popd done popddone
它可以追蹤記錄你切換的目錄并進(jìn)行入?;虺鰲?/p>
注意,當(dāng)使用pushd出現(xiàn)錯(cuò)誤時(shí),可能會(huì)丟失棧的記錄并且popd多次。因此你可能會(huì)想要在腳本中使用set -e(見(jiàn)上一篇文章)
當(dāng)然也可以用cd -,但是它不會(huì)使用棧——僅僅返回前一個(gè)目錄
cd ~cd /tmpcd blahcd - # Back to /tmpcd - # Back to 'blah'cd - # Back to /tmpcd - # Back to 'blah' ...
3) shopt vs set
這兩個(gè)命令困擾了我一陣子。
兩者之間有什么不同呢?
set在之前的文章已經(jīng)介紹過(guò)了,而shopt看起來(lái)與之相似。只輸入shopt會(huì)顯示一系列選項(xiàng):
$ shoptcdable_vars offcdspell oncheckhash offcheckwinsize oncmdhist oncompat31 offdotglob off
我在這里(here)找到了一些答案。
從根本上說(shuō),似乎有一系列的bash(和其他shells)建立在sh之上,而添加shopt命令則為設(shè)置額外的shell選項(xiàng)提供了一種方式
但是我也不確定……如果你知道為什么,請(qǐng)告訴我。
4)Here Docs 與 Here Strings
“Here Docs”是在shell中用一些語(yǔ)句創(chuàng)建的文件。
“訣竅”很簡(jiǎn)單。定義一個(gè)用于結(jié)束的單詞,則在這個(gè)單詞單獨(dú)出現(xiàn)在一行之前的所有輸入行將構(gòu)成文件。
像這樣:
$ cat > afile << SOMEENDSTRING> here is a doc> it has three lines> SOMEENDSTRING alone on a line will save the doc> SOMEENDSTRING$ cat afilehere is a docit has three linesSOMEENDSTRING alone on a line will save the doc$
注意:
· 如果結(jié)束單詞不是“單獨(dú)”出現(xiàn)在一行中,那它可以構(gòu)成文件
· SOMEENDSTRING通常是END,但這僅僅只是習(xí)慣
更鮮為人知的是“here string”:
$ cat > asd <<< 'This file has one line'
5)字符串變量的操作
以前你可能是像下面展示的那樣寫(xiě)代碼,用sed一類(lèi)的工具來(lái)操作字符串:
$ VAR='HEADERMy voice is my passwordFOOTER'$ PASS="$(echo $VAR | sed 's/^HEADER(.*)FOOTER/1/')"$ echo $PASS
但是你可能不知道bash本身也是可以的。
這意味著你可以省去大量的sed和awk。
一種重寫(xiě)上述代碼的方式如下所示:
$ VAR='HEADERMy voice is my passwordFOOTER'$ PASS="${VAR#HEADER}"$ PASS="${PASS%FOOTER}"$ echo $PASS
·#表示“從字符串開(kāi)頭開(kāi)始匹配并刪除所給的模式串”
·%表示“從字符串結(jié)尾開(kāi)始匹配并刪除所給的模式串”
在我的電腦上,后一種方法比前一種快兩倍。并且(令我吃驚的是),他的速度跟類(lèi)似功能的python腳本速度大致相當(dāng)
如果你想使用通配符(見(jiàn)前文)模式串并采用貪婪模式,你需要雙寫(xiě):
$ VAR='HEADERMy voice is my passwordFOOTER'$ echo ${VAR##HEADER*}$ echo ${VAR%%*FOOTER}
6)變量的默認(rèn)值
這些對(duì)寫(xiě)腳本來(lái)說(shuō)非常好用。
如果你有一個(gè)沒(méi)有賦值的變量,你可以像這樣給它“賦默認(rèn)值”
創(chuàng)建一個(gè)default.sh文件,寫(xiě)入如下內(nèi)容:
#!/bin/bashFIRST_ARG="${1:-no_first_arg}"SECOND_ARG="${2:-no_second_arg}"THIRD_ARG="${3:-no_third_arg}"echo ${FIRST_ARG}echo ${SECOND_ARG}echo ${THIRD_ARG}
現(xiàn)在執(zhí)行chmod +x default.sh并用./default.sh first second來(lái)運(yùn)行腳本:
觀察第三個(gè)參數(shù)的默認(rèn)值是如何被分配的,而不是前兩個(gè)。
你也可以直接用${VAR:=defaultval}(等號(hào),不是破折號(hào)),但是注意這不適用于腳本或函數(shù)中的位置變量。嘗試修改上面的腳本來(lái)看它是如何失敗的。
7)Traps
當(dāng)一個(gè)信號(hào)被送到腳本時(shí),內(nèi)建的trap可以用于“捕獲”
下面是我用在自己的chepci腳本中的一個(gè)例子:
function cleanup() { rm -rf "${BUILD_DIR}" rm -f "${LOCK_FILE}" # get rid of /tmp detritus, leaving anything accessed 2 days ago+ find "${BUILD_DIR_BASE}"/* -type d -atime +1 | rm -rf echo "cleanup done" } trap cleanup TERM INT QUIT
任何使用TERM信號(hào)的CTRL-C,CTRL-或終止程序的操作將會(huì)首先調(diào)用cleanup
注意:
·trap的邏輯可能非常棘手(例如處理信號(hào)競(jìng)爭(zhēng)條件)
·KILL信號(hào)不能以這種方式捕獲
但是大多數(shù)情況下,我會(huì)把它用于類(lèi)似上述的‘cleanup’中,來(lái)達(dá)成函數(shù)的目的。
8)Shell變量
了解可用的標(biāo)準(zhǔn)shell變量是非常值得的。這些是我最喜歡的。
RANDOM
不要依賴(lài)這個(gè)來(lái)加密堆棧,但你可以生成隨機(jī)數(shù)字,例如在腳本中創(chuàng)建臨時(shí)文件時(shí):
$ echo ${RANDOM}16313$ # Not enough digits?$ echo ${RANDOM}${RANDOM}113610703$ NEWFILE=/tmp/newfile_${RANDOM}$ touch $NEWFILE
REPLY
不在需要給read一個(gè)變量名稱(chēng)
$ readmy input$ echo ${REPLY}
LINENO 與 SECONDS
方便調(diào)試
$ echo ${LINENO}115$ echo ${SECONDS}; sleep 1; echo ${SECONDS}; echo $LINENO174380174381116
注意,即便使用;來(lái)隔開(kāi)命令,上面的代碼也要分兩行
TMOUT
可以用來(lái)超時(shí)讀取,在一些腳本中真的很好用
#!/bin/bashTMOUT=5echo You have 5 seconds to respond...readecho ${REPLY:-noreply}
9) Extglobs
如果你真的沉迷bash不能自拔,那么你可能想要增強(qiáng)你的通配功能。你可以通過(guò)設(shè)置shell中的extglob選項(xiàng)。這是設(shè)置方法:
shopt -s extglobA="12345678901234567890"B=" ${A} "
現(xiàn)在來(lái)看看你是否能指出以下這些語(yǔ)句各自的功能:
echo "B |${B}|"echo "B#+( ) |${B#+( )}|"echo "B#?( ) |${B#?( )}|"echo "B#*( ) |${B#*( )}|"echo "B##+( )|${B##+( )}|"echo "B##*( )|${B##*( )}|"echo "B##?( )|${B##?( )}|"
雖然它可能很有用,但是很難想象出一種你必須要用這種方式的情況。通常你會(huì)使用一些更適合相應(yīng)任務(wù)的工具(像sed)或者直接放棄bash去使用一些像python那樣的“合適的”編程語(yǔ)言。
10)關(guān)聯(lián)數(shù)組
談到移植到其他語(yǔ)言,一條重要的規(guī)則是,如果我需要用到數(shù)組,那么我會(huì)放棄bash,使用python(為此我甚至創(chuàng)建了一個(gè)Docker Container來(lái)運(yùn)行一個(gè)專(zhuān)門(mén)的工具)
知道讀到它我才知道,在bash中有關(guān)聯(lián)數(shù)組
以下是演示:
$ declare -A MYAA=([one]=1 [two]=2 [three]=3)$ MYAA[one]="1"$ MYAA[two]="2"$ echo $MYAA$ echo ${MYAA[one]}$ MYAA[one]="1"$ WANT=two$ echo ${MYAA[$WANT]}
注意僅適用于bash4.x+版本
-
程序
+關(guān)注
關(guān)注
116文章
3762瀏覽量
80757 -
Shell
+關(guān)注
關(guān)注
1文章
363瀏覽量
23259 -
Bash
+關(guān)注
關(guān)注
0文章
57瀏覽量
10161
原文標(biāo)題:有關(guān)bash,我希望我能知曉的十件事
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論