日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux sed p变量,Linux sed 命令详解系列教程之各种问题解决

發(fā)布時(shí)間:2024/4/19 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux sed p变量,Linux sed 命令详解系列教程之各种问题解决 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文目錄:

1 sed中使用變量和變量替換的問題

2 反向引用失效問題

3 "-i"選項(xiàng)的文件保存問題

4 貪婪匹配問題

5 sed命令"a"和"N"的糾葛

1.sed中使用變量和變量替換的問題

在腳本中使用sed的時(shí)候,很可能需要在sed中引用shell變量,甚至想在sed命令行中使用變量替換。也許很多人都遇到過這個(gè)問題,但引號卻死活調(diào)試不出正確的位置。其實(shí)這不是sed的問題,而是shell的特性。搞懂sed如何解決引號的問題,對理解shell引號問題有很大幫助,觸類旁通,以后在使用awk、MySQL等等自帶語法解析的工具時(shí)就不會再疑惑。

例如下面想輸出a.txt的倒數(shù)5行的語句。可能順手就寫出了下面的命令行:

total=`wc -l

sed -n '$((total-4)),$p' a.txt

但很不幸,這會報(bào)錯(cuò)。一方面,"$"在sed中是特殊符號,放在定址表達(dá)式中時(shí),它表示的是輸入流的最后一行的標(biāo)記。而$(())中也出現(xiàn)了"$"符號,這會讓sed去解析該符號。另一方面,$(())這部分是使用shell計(jì)算而不是使用sed計(jì)算的,因此必須要將其暴露給shell,以便能讓shell能解析它。

再說說shell中單引號、雙引號和不加引號的情況。

單引號:單引號內(nèi)的所有字符變?yōu)樽置娣枴5⒁?#xff1a;單引號內(nèi)不能再使用單引號,即使使用了反斜線轉(zhuǎn)義也不允許。

雙引號:雙引號內(nèi)的所有字符變?yōu)樽置娣?#xff0c;但"\"、"$"、"`"(反引號)除外,如果開啟了"!"引用歷史命令時(shí),則感嘆號也除外。

不使用引號:幾乎等同于使用了雙引號,但會進(jìn)行大括號和波浪號擴(kuò)展。

上面關(guān)于雙引號的情況,描述的并不是真正的完整,但已足夠。這些只是它們的字面意義,引號真正的意義在于:決定命令行中哪些"單詞"需要被shell解析,也決定哪些是字面意義不用被shell解析。

顯然,單引號內(nèi)所有字符都成為了字面符號,shell不會解析其內(nèi)任何單詞,例如單引號內(nèi)變量不再被解析、命令替換和算術(shù)運(yùn)算不再執(zhí)行、不會進(jìn)行路徑擴(kuò)展等等。總之,單引號內(nèi)的字符全是普通字符,如果某些字符需要交給自帶解析功能的命令解析,必須使用單引號。例如,"$"、"!"和"{}"在sed中均有特殊意義,要想讓sed能解析它們,必須對它們使用單引號,否則必出錯(cuò),或者產(chǎn)生歧義。例如下面3個(gè)sed語句中的符號都必須使用單引號才能得到正確結(jié)果。

sed '$d' filename

sed '1!d' filename

sed -n '2{p;q}' filename

而想要讓特殊字符被shell解析,必須不能將其包圍在單引號中,可以使用雙引號,也可以不加任何引號,即使不加引號時(shí)可能看上去很怪異。例如,上面的算術(shù)運(yùn)算$(())是想被shell解析的,因此必須使用單引號或者不加引號將其暴露給shell。所以正確的語句是:

sed -n $((total-4))',$p' a.txt

sed -n "$((total-4))"',$p' a.txt

sed -n "$((total-4)),\$p" a.txt

從肉眼看上去,這個(gè)語句的引號加的真的很怪異。但shell又不管丑美,它是死的,在劃分命令行的時(shí)候它有自己的一套規(guī)則,規(guī)則怎樣就怎樣劃分。

于是,關(guān)于sed如何和shell交互的問題可以得出一套結(jié)論:

遇到需要被shell解析的都不加引號,或者加雙引號;

遇到shell和所執(zhí)行命令共有的特殊字符時(shí),要想被sed解析,必須加單引號,或者在雙引號在加反斜線轉(zhuǎn)義;

那些無關(guān)緊要的字符,無論加什么引號。

因此,使用命令替換的方式讓sed輸出倒數(shù)5行的語句如下:

sed -n `expr $(wc -l

上面的語句中,`expr $(wc -l

更復(fù)雜一些,在sed的正則表達(dá)式中使用變量替換。例如,輸出a.txt中以變量str字符串開頭的行到最后一行。

str="abc"

sed -n /^$str/',$p' a.txt

因?yàn)闆]有使用任何引號,所以$str能如期被shell替換成"abc"。這個(gè)命令還有多種寫法:

sed -n '/^'$str'/,$p' a.txt

sed -n "/^$str"'/,$p' a.txt

sed -n "/^$str/,\$p" a.txt

sed -n "/^$str/,"'$'p a.txt

給一個(gè)稍難一些的sed符號使用問題。將/etc/shadow中的最后一行的密碼部分替換成"$1$123456$wOSEtcyiP2N/IfIl15W6Z0"。

[root@xuexi ~]# tail -n 1 /etc/shadow

userX:$6$hS4yqJu7WQfGlk0M$Xj/SCS5z4BWSZKN0raNncu6VMuWdUVbDScMYxOgB7mXUj./dXJN0zADAXQUMg0CuWVRyZUu6npPLWoyv8eXPA.::0:99999:7:::

替換語句如下:

old_pass="$(tail -n 1 /etc/shadow | cut -d':' -f2)"

new_pass='$1$123456$wOSEtcyiP2N/IfIl15W6Z0'

sed -n '$'s%$old_pass%$new_pass% /etc/shadow

由于old_pass和old_pass中包含了"/"和"$"符號,因此"s"命令的分隔符使用了"%"替代。再仔細(xì)觀察new_pass,其內(nèi)有"."符號,這是正則表達(dá)式的元字符,因此它還可以匹配其他情況。

2.反向引用失效問題

當(dāng)正則表達(dá)式中使用二者選一的選項(xiàng)"|"時(shí),如果分組括號()中的內(nèi)容沒有參與匹配,后向引用將不起作用。例如(a)\1u|b\1將只匹配"aau"的行,不匹配"ba"的行,因?yàn)樵诙哌x一的第二個(gè)正則中\(zhòng)1代表的分組沒有參與匹配,所以第二個(gè)正則中的\1失效,但是第一個(gè)正則中的\1有效。

這是正則匹配的問題,不只是sed,其它使用基礎(chǔ)正則和擴(kuò)展正則引擎的工具也一樣會有這樣的問題。

另外,在s命令中使用反向引用時(shí),將不會引用"s"命令外面的分組。例如:

echo "ab3456cd" | sed -r "/(ab)/s/([0-9]+)/\1/"

得到的結(jié)果將是ab3456cd,而不是ababcd,而且如果此時(shí)使用\2引用,則會報(bào)錯(cuò)"invalid reference \2 on 's' command's RHS"。

3."-i"選項(xiàng)的文件保存問題

sed是通過創(chuàng)建一個(gè)臨時(shí)文件,并將輸出寫入到該臨時(shí)文件,然后重命名該臨時(shí)文件為源文件來實(shí)現(xiàn)文件保存的。因此,sed會無視文件的只讀性。

是否允許重命名或移入或刪除文件,是由文件所在目錄的權(quán)限控制的。如果目錄為只讀權(quán)限,則sed無法使用"-i"選項(xiàng)保存結(jié)果,即使該文件具有可讀權(quán)限。

4.貪婪匹配問題

所謂的貪婪匹配,是指當(dāng)正則表達(dá)式能匹配多個(gè)內(nèi)容時(shí),取最長的那個(gè)。最簡單的例子,給定數(shù)據(jù)"abcdsbaz",正則表達(dá)式"a.*b"可以匹配該數(shù)據(jù)中"ab"和"abcdsb",由于貪婪匹配,它會取最長的"abcdsb"。

echo "abcdbaz" | grep -o "a.*b"

abcdb

基礎(chǔ)正則表達(dá)式和擴(kuò)展正則表達(dá)式一直以來的一個(gè)不足之處在于無法原生態(tài)克服貪婪匹配,像Perl正則或其他編程語言的正則實(shí)現(xiàn)的比較完整,在"*"或"+"這種多次重復(fù)的匹配后加上一個(gè)"?"就可以明確表示采取懶惰匹配的模式,例如"a.*?b"。

echo "abcdbaz" | grep -P -o "a.*?b"

ab

想要克服基礎(chǔ)正則或擴(kuò)展正則的貪婪匹配,只能"投機(jī)取巧"地采用不包含符號"[^]"來實(shí)現(xiàn)。例如上面的:

echo "abcdbaz" | grep -o "a[^b]*b"

ab

這種投機(jī)取巧的方式,性能比較差,因?yàn)榛A(chǔ)或擴(kuò)展正則表達(dá)式的引擎總是會先匹配出最長的內(nèi)容,然后往回匹配,這稱為"回溯"。例如"abcdsbaz"在被"a[^b]*b"匹配時(shí),先匹配出"abcdsb",再一個(gè)字符一個(gè)字符地回退匹配,直到回退到第一個(gè)"b"才是最短的結(jié)果。

再例如,/etc/passwd文件中每行數(shù)據(jù)的格式如下:

rootx:0:0:root:/root:/bin/bash

如何使用sed向/etc/passwd中的每個(gè)用戶問聲好,輸出格式大致為:"hello root"、"hello nobody"。

首先,得取出文件中的第一列,即用戶名。但由于該文件中所有行都采用冒號分隔各字段,想要使用正則表達(dá)式匹配得到第一段,必須克服貪婪匹配。語句如下:

sed -r 's/^([^:]*):.*/hello \1/' /etc/passwd

注意,sed采用的是基礎(chǔ)正則和擴(kuò)展正則引擎,在克服貪婪匹配時(shí),它必須先匹配出最長的,再回溯出最短的。

如果想取/etc/passwd中的前兩個(gè)字段呢?只需將克服貪婪的正則當(dāng)作整體重復(fù)一次即可。

sed -r 's/^([^:]*):([^:]*):.*/hello \1 \2/' /etc/passwd

取第三個(gè)字段?

sed -r 's/^([^:]*:){2}([^:]*):.*/hello \2/' /etc/passwd

取第三和第五個(gè)字段?沒辦法,只能將第四個(gè)字段顯式標(biāo)注出來。

sed -r 's/^([^:]*:){2}([^:]*):([^:]*):([^:]*):/hello \2 \4/' /etc/passwd

取第三道第5字段?更簡單,重復(fù)3次就可以了。

sed -r 's/^([^:]*:){2}(([^:]*:){3}).*/hello \2/' /etc/passwd

但這樣的結(jié)果中,第3到第5字段中必然會包含":"分隔符,想要去除它?洗洗睡吧!sed本就不擅長處理字段,克服貪婪匹配本就讓表達(dá)式變得很復(fù)雜不易讀,而且效率還不高。用它處理字段,絕對是吃撐了。

5.sed命令"a"和"N"的糾葛

sed的"a"命令作用是將提供的文本數(shù)據(jù)隊(duì)列化在內(nèi)存中,然后在模式空間內(nèi)容輸出時(shí)追加在輸出流的尾部一并輸出。

例如,在匹配行"ccc"后插入一行數(shù)據(jù)"matched successful"。

echo -e "aaa\nbbb\nccc\nddd" | sed '/ccc/a matched successful'

aaa

bbb

ccc

matched successful

ddd

咋一使用"a"命令,很順利,沒毛病。但是結(jié)合"N"試試看?

echo -e "aaa\nbbb\nccc\nddd" | sed '/ccc/{a\

matched successful

;N}'

aaa

bbb

matched successful

ccc

ddd

不是追加在尾部嗎,怎么跑匹配行的前面去了?即使"N"讀取了下一行,也應(yīng)該是追加在"ddd"的下一行吧?想要真正弄明白這個(gè)問題,對sed模式空間的輸出機(jī)制必須了如指掌,可以參考Linux sed 命令詳解系列教程之入門篇。此處簡單描述下"N"命令的輸出機(jī)制。

無論是sed自動讀取下一行,還是"n"或"N"命令讀取下一行,只要有讀取動作,在其前面必然會輸出模式空間的內(nèi)容。當(dāng)"N"讀取下一行時(shí),首先���會判斷是否還有下一行可供讀取,如果有,則先鎖住模式空間,然后自動輸出并清空模式空間,再解鎖模式空間并向其尾部追加一個(gè)換行符"\n",最后讀取下一行追加到換行符尾部。由于模式空間被鎖住,使得自動輸出時(shí)輸出流是空流,也同樣無法清空模式空間。注意,它不是禁止輸出,雖然輸出空流的結(jié)果和禁止輸出是一樣的,但輸出空流它有輸出動作,有輸出流,會寫入標(biāo)準(zhǔn)輸出,而禁止輸出則沒有輸出動作。如果沒有下一行可供讀取,則自動輸出模式空間、清空模式空間并退出sed程序。過程大致如下所描述:

if [ "$line" -ne "$last_line_num" ];then

lock pattern_space;

auto_print;

remove_pattern_space;

unlock pattern_space;

append "\n" to pattern_space;

read next_line to pattern_space;

else

auto_print;

remove_pattern_space;

exit;

fi

回到"a"命令和"N"命令結(jié)合的問題上。之所以"a"命令的隊(duì)列化文本會插入在匹配行的前面,問題就出在輸出空流上。"N"在準(zhǔn)備讀取下一行時(shí),它有輸出動作,即使輸出結(jié)果為空。而"a"命令是時(shí)刻等待sed輸出流的,只要一有輸出流,立馬就會追上去追加在輸出流的屁股后面。因此,"matched successful"會追加在空流的尾部,追加之后"N"才會讀入下一行,最后輸出模式空間中的內(nèi)容"ccc\nddd",也就得到前面"有悖期待"的結(jié)果。

總結(jié)

以上是生活随笔為你收集整理的linux sed p变量,Linux sed 命令详解系列教程之各种问题解决的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。