2016-09-06 89 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