2013-04-12 82 views
33

我正在使用sed更新運行時的json配置文件。 有時,當模式不以JSON文件sed退出,返回代碼匹配,仍爲0sed的返回碼不匹配

返回0表示成功完成,但爲什麼sed返回0,如果它不找到合適的模式和更新文件?有沒有解決方法?

謝謝!

+6

是的,就'sed'而言,它做了它的工作:它試圖編輯文件。如果文件不可讀或類似的話,它會返回一個錯誤代碼。總之,我不認爲'sed'是決定*文件中是否出現模式*的最佳工具。 – cnicutar

+0

@cnicutar很多人發表評論作爲答案,但我認爲你只是在評論區放回答。我猜OP不僅希望檢查模式匹配,他希望做一些事情,如果模式匹配..像'/ pat/s/foo/bar/...' – Kent

+0

@Kent這就是爲什麼我沒有發佈一個回答。我解釋了爲什麼'sed'這樣做,但無法提出一個可接受的解決方案。我想到的所有事情都需要在'sed'之前調用一個單獨的命令,以便確定文件是否匹配。理想情況下,應該有一些解決方案(可能'awk'和'gsub'?),可以在一個命令中完成。 – cnicutar

回答

31

as @cnicutar評論說,命令的返回碼意味着命令是否成功執行。與您在代碼/腳本中實施的邏輯無關。

,如果您有:

echo "foo"|sed '/bar/ s/a/b/' 

的sed將返回0但如果你寫一些語法/表達錯誤,或者輸入/文件不存在,sed中不能執行您的要求,用sed將返回1 。

解決方法

這其實不是解決辦法。 SED具有q命令:(從手冊頁):

q [exit-code] 

在這裏你可以定義退出代碼,只要你想。例如:

匹配情況:

kent$ echo "foo"|sed '/foo/ {s/f/b/;q}'           
boo 

kent$ echo $? 
0 

無可比擬的情況:

kent$ echo "trash"|sed '/foo/{s/f/b/;q}; /foo/!{q100}' 
trash 

kent$ echo $? 
100 

我希望這回答了你的問題。

編輯

我必須補充的是,上面的例子是隻在一個行的處理。我不知道你的具體要求。當你想得到exit 1。一行不匹配或整個文件。如果search-string發現它

sed '/search-string/{s//replacement-string/;h};${x;/./{x;q0};x;q1}' file 

:如果整個文件不匹配的情況下,你可能會考慮AWK,甚至做你的文字處理之前grep ...

+0

純粹迷人。我在看'q',但不知道該怎麼做。 – cnicutar

+0

太棒了!這對我有用。非常感謝! – bram

+2

這個答案很適合GNU sed,但是請注意'q'選項不能移植到BSD(Mac)sed。 – spinup

38

這可能會爲你工作(GNU SED)將被替換爲replacement-string,並且在文件結尾sed將以0返回代碼退出。如果沒有替換髮生,返回碼將是1

更詳細的解釋:

在sed用戶具有在他的處置兩個寄存器:模式空間(PS),其中電流線被加載到(減去換行)和備用寄存器稱爲保持空間(HS)最初是空的。

總的想法是使用HS作爲標誌來指示是否發生了替換。如果文件末尾的HS仍爲空,則不會進行更改,否則會發生更改。

命令/search-string/匹配search-string與無論是在PS和如果它被發現含有以下大括號之間的search-string的命令被執行。

首先取代s//replacement-string/(SED使用最後的regexp即search-string,如果左手側是空的,所以s//replacement-string相同s/search-string/replacement-string/)並按照這個h命令使PS的副本,並把它放在HS。

sed命令$用於識別文件的最後一行,然後出現以下內容。

首先,x命令交換兩個寄存器,所以HS成爲PS,PS成爲HS。

然後在PS中搜索任何字符/./.表示匹配任何字符)記住HS(現在的PS)最初是空的,直到發生替換。如果條件爲真,則再次執行x,然後執行q0命令,該命令結束所有sed處理並將返回碼設置爲0。否則,執行x命令並將返回碼設置爲1

N.B.儘管q退出了sed處理,但它並不妨礙通過sed重新組裝se並按正常方式打印。

另一種選擇:

sed '/search-string/!ba;s//replacement-string/;h;:a;$!b;p;x;/./Q;Q1' file 

或:

sed '/search-string/,${s//replacement-string/;b};$q1' file 
+0

感謝您的建議。 – bram

+1

+1我很難讓Kent的例子工作。我也嘗試過你的最後一個,也無法讓它工作。我確定它與我正在使用的搜索字符串有關。然而,你的線程中的第一個很好用! –

+1

用於將'q'放入'$':-) – anishsane

0

我本來想通過比賽時被發現戒菸截斷文件(並排除匹配的行)。當在文件末尾添加行的進程可能會重新運行時,這很方便。 「Q; Q1」不起作用,但只是「Q1」,如下所示:

如果sed -i'/ text我想查找/ Q1'file.txt 然後 在文件結尾插入空白行+新行 fi 只插入沒有空行的新行

10

這些答案都太複雜了。編寫一些使用grep來查找你想替換的東西是否存在的shell腳本有什麼問題,然後用sed替換它?

grep -q $TARGET_STRING $file 
if [ $? -eq 0 ] 
then 
    echo "$file contains the old site" 
    sed -e "s|${TARGET_STRING}|${NEW_STRING}|g" .... 
fi 
+2

如果'$ file'是'/ dev/stdin'則不起作用。 – Elena

+1

這也不適用於沒有Cygwin的Windows ;-) – Cameron

+0

它更長,但絕對更可讀,謝謝! –

1

下面是我們與sed -rnsed -r使用該模式。

整個搜索和替換命令(「s/.../.../...」)是可選的。如果使用搜索和替換,爲了速度並且已經匹配$ matchRe,我們使用盡可能快的$ searchRe值。字符不需要重新驗證,並且。{$ len}用於模式的固定長度部分。

找不到的返回值是$ notFoundExit。

/$matchRe/{s/$searchRe/$replacement/$options; Q}; q$notFoundExit 

原因有以下幾點:

  • 沒有時間既匹配和不匹配的情況下
  • 無需浪費時間複製到或從緩衝區
  • 沒有多餘的樹枝
  • 合理的靈活性,浪費了測試

改變Q命令的情況會根據退出何時發生而改變行爲。涉及將布爾邏輯應用於多行輸入的行爲在解決方案中需要更多的複雜性。

0

正如我們已經知道的那樣,當sed不匹配時,它只是返回它的輸入字符串 - 沒有發生錯誤。確實,輸入和輸出字符串之間的差異意味着匹配,但匹配並不意味着字符串的差異;畢竟sed可以簡單地匹配所有的輸入字符。 該缺陷將在下面的示例中創建

h=$(echo "$g" | sed 's/.*\(abc[[:digit:]]\).*/\1/g')  
if [ ! "$h" = "$g" ]; then  
    echo "1" 
else  
    echo "2"  
fi 

其中g=Xabc1得到1,同時設定g=abc1給出2;然而這兩個輸入字符串都是由sed匹配的!因此,很難確定sed是否匹配。 A液:

在這種情況下
h=$(echo "fix${g}ed" | sed 's/.*\(abc[[:digit:]]\).*/\1/g') 
if [ ! "$h" = "fix${g}ed" ]; then  
    echo "1" 
else  
    echo "2"  
fi 

1打印如果且僅-如果sed的已匹配。