2016-09-06 92 views
8

我試圖用sed做一些base64替換。Sed使用捕獲組作爲參數替換bash命令的輸出

我想要做的是這樣的:

sed -i "s|\(some\)\(pattern\)|\1 $(echo "\2" | base64 -d)|g" myFile 

在英語中,這將是:

  • 數學的模式
  • 捕捉組
  • 使用捕獲組bash命令
  • 使用此命令的輸出作爲替換字符串

到目前爲止,我的命令不起作用,因爲\2只能由SED,而不是通過bash命令我打電話知道。

有什麼優雅的解決方案,我必須將捕獲組傳遞給我想要使用輸出的命令?


編輯

這裏是我想要做的一個小例子:

我有以下文件:

someline 
someline 
Base64Expression stringValue="Zm9v" 
someline 
Base64Expression stringValue="YmFy" 

而且我想,以取代通過純文本的base64:

someline 
someline 
Base64Expression stringValue="foo" 
someline 
Base64Expression stringValue="bar" 

在未來,我必須做反向操作(該解碼文件中base64編碼字符串)

我用awk開始,但我雖然能得到與SED簡單(更優雅) 。到目前爲止,有AWK我有這個(其中$bundle是我編輯的文件):

#For each line containing "Base64Expression" 
#Put in the array $substitutions[]: 
# The number of the line (NR) 
# The encoded expression ($2) 
# The decoded expression (x) 
substitutions=($(awk -v bd=$bundle ' 
    BEGIN { 
     # Change the separator from default 
     FS=""" 
     ORS="," 
     OFS="," 
    } 
    /Base64Expression/ { 
     #Decode the base64 lines 
     cmd="echo -ne \""$2"\" | base64 -d" 
     cmd | getline x 

     if ((cmd | getline) == 0){ 
      print NR, $2, x 
     } 
    } 
' $bundle)) 

# Substitute the encoded expressions by the decoded ones 
# Use the entries of the array 3 by 3 
# Create a sed command which takes the lines numbers 
for ((i=0; i<${#substitutions[@]}; i+=3)) 
do 
    # Do the substitution only if the string is not empty 
    # Allows to handle properly the empty variables 
    if [ ${substitutions[$((i+1))]} ] 
    then 
     sed -i -e "${substitutions[$i]}s#${substitutions[$((i+1))]}#${substitutions[$((i+2))]}#" $bundle 
    fi 
done 
+0

這是不可能的,因爲'$(echo「\ 2」| base64 -d)'是先完成的。此外,如果在sed中使用shell變量,則需要用雙引號替換單引號。 – sjsam

+0

'awk'是爲這樣的處理而設計的。但是,我們需要查看最小的一組樣本數據以重現您的問題以及爲了幫助您輸入所需的輸出。請編輯您的Q以包含該信息。祝你好運。 – shellter

+0

@shellter我編輯了我用awk做過的問題。 @ sjsam,謝謝你指出我的引用,我也編輯了這個。 – statox

回答

11

您可以使用GNU sede來替換字符串傳遞給用於評估的外殼。這樣一來,你可以說:

printf "%s %s" "something" "\1" 

\1持有捕獲組。全部在一起:

$ sed -r 's#match_([0-9]*).*#printf "%s %s" "something" "\1"#e' <<< "match_555 hello" 
something 555 

當您想要對捕獲的組執行某些shell操作時(例如在這種情況下),這會非常方便。

那麼,讓我們捕捉到線的第一部分,則需要的部分進行編碼,最後剩下的。一旦做到這一點,讓我們來打印這些碎片重新與printf觸發base64 -d使用對第二層:在

sed -r '/^Base64/s#(.*;)([^\&]*)(&.*)# printf "%s%s%s" "\1" $(echo "\2" | base64 -d) "\3";#e' file 
#  ^^^^^^^ ^^^ ^^^^^^ ^^^      ^^^^^^^^^^^^^^^^^^^^^^^^  ^
#   | first part | the rest    encode the 2nd captured group  | 
#   |    |                | 
#   |   important part          execute the command 
#   | 
# on lines starting with Base64, do... 

的想法來源於此superb answer by anubhava如何:

$ sed -r '/^Base64/s#(.*;)([^\&]*)(&.*)# printf "%s%s%s" "\1" $(echo "\2" | base64 -d) "\3";#e' file 
someline 
someline 
Base64Expression stringValue=&quot;foo&quot; 
someline 
Base64Expression stringValue=&quot;bar&quot; 

一步一步在sed中更改日期格式?

+1

現在是一些偉大的SED技術!使用'e'標誌與'printf'結合的技巧是我需要的!非常感謝! – statox

3

聽起來好像這是你想要做什麼:

$ cat tst.awk 
BEGIN { FS=OFS="&quot;" } 
/^Base64Expression/ { 
    cmd="echo -ne \""$2"\" | base64 -d" 
    if ((cmd | getline x) > 0) { 
     $2 = x 
    } 
    close(cmd) 
} 
{ print } 

$ awk -f tst.awk file 
someline 
someline 
Base64Expression stringValue=&quot;foo&quot; 
someline 
Base64Expression stringValue=&quot;bar&quot; 

假設你echo | base64是正確的做法。

+0

我不確定我瞭解如何使用'{print}'語句。我不是一個awk老兵,在沒有正則表達式或'BEGIN | END'的語句使我困惑之前。如果你能解釋一下你的代碼是如何工作的,那將是非常好的。 – statox

+0

我剛剛複製你的代碼,修正了語法並添加了一個'print'。 Awk由' {012}}配置爲默認條件爲true,默認操作是打印當前記錄(默認爲一行)。在我的腳本中自帶的{print}只是打印每一行。我推薦Arnold Robbins編寫的第4版Effective Awk Programming。 –

+1

好的,謝謝你的改寫,現在更清晰了。我一定會找這本書的。 – statox