歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> SHELL編程

Linux shell 命令和正則表達式

今天在Fedora20系統上編譯VPP項目時遇到了一個問題,在最終編譯並且使用rpmbuild生成的rpm安裝包不正確,我們需要對生成rpm包的spec文件做一些小的修改。

 首先我們來看看VPP自帶的生成rpm包的spec描述文件,該文件為${VPP_TOPDIR}/build-root/rpm/vpp.spec, 我們可以打開看看該文件的內容:

 其中在%install 段裡面有如下的命令

 1 #  2 # libraries
 3 #
 4 mkdir -p -m755 %{buildroot}%{_libdir}
 5 for file in $(find %{_vpp_install_dir}/*/lib* -type f -name '*.so.*.*.*' -print )
 6 do
 7     install -p -m 755 $file %{buildroot}%{_libdir}
 8 done
 9 for file in $(cd %{buildroot}%{_libdir} && find . -type f -print | sed -e 's/^\.\///')
 do
     # make lib symlinks
     ( cd %{buildroot}%{_libdir} && 
           ln -fs $file $(echo $file | sed -e 's/\(\.so\.[0-9]\+\).*/\1/') )
 done

 這裡首先在%{buildroot}目錄裡面創建lib目錄,然後調用install命令將編譯出來的所有的VPP項目的lib文件拷貝到%{buildroot}目錄裡面的lib目錄裡面。

現在我們來看9~14行的一個 for循環命令,該命令主要是完成這樣的一個功能:將%{buildroot}目錄裡面的lib目錄裡面的所有的庫文件建立一個軟鏈接文件。

 比如:假如現在在%{buildroot}目錄裡面的lib目錄裡面有一個庫文件libvnet.so.18.0.0, 那麼上述for循環完成之後就在同一目錄下建立了一個軟鏈接文件libvnet.so.18並指向libvnet.so.18.0.0庫文件。

 現在我們來一步步的分析上面的9~14行的這個for循環語句的工作過程,我們假設在/usr/lib64/目錄下有2個庫文件,一個是libvpp.so.0.0.0, 一個是libvnet.so.18.0.0.

首先我們來看第9行的for語句後面的一個shell命令:

 $(cd %{buildroot}%{_libdir} && find . -type f -print | sed -e 's/^\.\///')

 那麼等價於執行下面的一條命令:

$(cd /usr/lib64/ && find . -type f -print | sed -e 's/^\.\///')

這條命令是兩條命令組合而成,首先執行cd /usr/lib64/切換工作目錄到/usr/lib64/目錄下,然後執行後續的find命令。

隨後執行 find . -type f -print 命令的結果如下:

./libvpp.so.0.0.0

./libvnet.so.18.0.0

這裡find命令的查找輸出結果前面都帶有路徑的。然後將find命令查找的輸出結果通過管道重定向到sed命令中,再來分析後面的sed命令。

sed -e 's/^\.\///':   查找行首以./開頭的行並將./替換為空, 這裡^表示匹配行首, 後面有兩個轉義符分別轉義"點(.)"和"斜槓(/)",  s動作表示查找替換

那麼經過sed命令處理之後的find查找結果就變為如下的結果了:

find . -type f -print | sed -e 's/^\.\///'    經過sed處理後的find查找結果全部去掉了前面的路徑了,該命令最終結果如下了:

libvpp.so.0.0.0

libvnet.so.18.0.0

至此,for循環中的file變量值就有了,file變量的值是集合{libvpp.so.0.0.0, libvnet.so.18.0.0}了。

下面我們再來分析for循環中的循環體語句。

( cd %{buildroot}%{_libdir} && ln -fs $file $(echo $file | sed -e 's/\(\.so\.[0-9]\+\).*/\1/') )

 我們可以在現在舉的這個例子裡面將上面的命令進行替換展開:

( cd /usr/lib64/ && ln -fs libvpp.so.0.0.0 $(echo libvpp.so.0.0.0 | sed -e 's/\(\.so\.[0-9]\+\).*/\1/') )

( cd /usr/lib64/ && ln -fs libvnet.so.18.0.0 $(echo libvnet.so.18.0.0 | sed -e 's/\(\.so\.[0-9]\+\).*/\1/') )

 我們具體來分析其中的sed命令,這裡有一個正則表達式我們假設將正則表達式展開,那麼得到如下的一個sed命令:

$(echo libvpp.so.0.0.0 | sed -e 's/(.so.[0-9]+).*/\1/')

注意:上述sed命令的正則表達式沒有加轉義字符啊。

 (.so.[0-9]+).*     // (...)表示匹配子串並保存匹配的字符,[0-9]表示匹配1個數字字符,[0-9]+表示匹配1個或者多個數字字符,.表示匹配一個非換行符的任意字符,*表示匹配0個或者多個字符

\1//表示在這裡直接引用前面查找匹配子串時保存的匹配字符

經過上面的分析,我們可以得出下面的shell命令運行的結果:

$(echo libvpp.so.0.0.0 | sed -e 's/(.so.[0-9]+).*/\1/')           //得到的結果字符串是: libvpp.so.0

$(echo libvnet.so.18.0.0 | sed -e 's/\(\.so\.[0-9]\+\).*/\1/') //得到的結果字符串是:libvnet.so.18

然後調用的ln -sf命令直接就創建了2個軟鏈接文件:

libvpp.so.0-------->libvpp.so.0.0.0

libvnet.so.18--------->libvnet.so.18.0.0

 

雖然上面的shell命令創建了2個軟鏈接文件,但是我們知道在Linux下程序引用動態鏈接庫文件的時候一般習慣性使用-lvpp, -lvnet等來指定,這樣一來依賴的庫文件形式就是libvpp.so和libvnet.so了,而不是libvpp.so.0和libvnet.so.18了。

因此我們還需要創建2個軟鏈接文件libvpp.so和libvnet.so, 也分別軟鏈接到libvpp.so.0.0.0和libvnet.so.18.0.0。

我們只需要將上面的for循環修改一下即可,我們修改如下:

for file in $(cd %{buildroot}%{_libdir} && find . -type f -print | sed -e 's/^\.\///') do # make lib symlinks ( cd %{buildroot}%{_libdir} &&            ln -fs $file $(echo $file | sed -e 's/\(\.so\.[0-9]\+\).*/\1/')  &&
ln -sf $file $(echo $file | sed -e 's/\(\.so\).*/\1/') ) done

這樣在for循環執行完之後,就在/usr/lib64目錄裡面分別創建了4個軟鏈接文件了,其關系如下:

libvpp.so-------->libvpp.so.0.0.0

libvpp.so.0-------->libvpp.so.0.0.0

libvnet.so--------->libvnet.so.18.0.0

libvnet.so.18-------->libvnet.so.18.0.0 

 具體的關於sed命令的使用和正則表達式的詳細說明,請參考如下的links:

http://man.linuxde.net/sed

http://www.infoq.com/cn/news/2011/07/regular-expressions-6-POSIX

Copyright © Linux教程網 All Rights Reserved