bash脚本:在特定行之间查找文件中的内容并在内容上运行命令,用命令输出替换旧内容

时间:2014-03-04 20:30:07

标签: bash shell replace find gnupg

我是脚本编写的真正新手,之前只使用一些vars,ifs,简单的grep,awk等命令制作了真正的简单脚本。

问:我有几千个带有明文的文件(电子邮件)和(有时)几个独立的GPG加密文本部分,如下所示:

several lines of
cleartext stuff (more specifically: email headers)

-----BEGIN PGP MESSAGE-----
RTDHNRFSGNRTDHNRFSGNRTDHNRFSGN
RTDHNRFSGNRTDHNRFSGNRTDHNRFSGN
-----END PGP MESSAGE-----

some more lines
of cleartext

-----BEGIN PGP MESSAGE-----
WPGLUFPJUWPGLUFPJUWPGLUFPJU
WPGLUFPJUWPGLUFPJUWPGLUFPJU
-----END PGP MESSAGE-----

我正在尝试创建一个(最好)bash脚本,该脚本遍历文件夹中的所有文件,查找GPG加密文本的每个实例,解密它,并用解密的文本替换旧的加密文本,然后保存文件。 因此,当脚本完成时,上面的假设文件如下所示:

several lines of
cleartext stuff (more specifically: email headers)

decrypted message #1

some more lines
of cleartext

decrypted message #2

当尝试使用GPG解密文件时,GPG将跳过所有明文内容并输出第一个解密消息。

所以我需要类似于while循环的东西,以便独立查找以“----- BEGIN PGP MESSAGE -----”开头的所有实例,并以“----- END PGP MESSAGE-”结尾----“并在其上使用GPG命令,然后用GPG命令的输出替换该实例。然后继续下一个加密文本实例。

到目前为止,我只有这几行,但他们显然没有正确地做我想要的。我不想在每个单独的文件上使用该脚本。而且我不想使用临时文件,我想有更好的方法来完成所有这些。

#!/bin/bash

TEMPFILE="${1}.tmp"

## grep only the relevant gpg lines to decrypt.
## this will output ALL encrypted instances to $TEMPFILE
sed -n '/^-----BEGIN PGP MESSAGE/,/^-----END PGP MESSAGE/p' "$1" > "$TEMPFILE"

## decrypt. this will only give me the decrypted output
## of the first encrypted instance in $TEMPFILE.
## and I don't know how to shove this into the proper place in the original file.
gpg --batch -d --no-tty --output "${1}.dc.eml" "$TEMPFILE"

## remove $TEMPFILE
rm "$TEMPFILE"

这是我编写的脚本语言,希望能够更好地解释我想要做的事情:

for all files in folder; do
    while i can find an instance of "-----BEGIN PGP" to "-----END PGP"; do
        command: gpg decrypt > $tempvar
        command: replace the instance of "-----BEGIN PGP" to "-----END PGP" with $tempvar
    end while
end for

这可能很容易实现(我希望),但我已经解决了这几天的解密困境,我无法正确地弄清楚如何去做。任何有关正确方向的帮助或提示对我都有很大的帮助。

编辑:最终代码,感谢格伦杰克曼! :

for file in *; do
    in_pgp_section=false
    pgp_text=""

    while IFS= read -r line; do
        if [[ $line == *BEGIN\ PGP\ MESSAGE* ]]; then
            in_pgp_section=true
        fi

        if ! $in_pgp_section; then
            printf "%s" "$line"
            continue
        fi

        pgp_text+="$line"$'\n'

        if [[ $line == *END\ PGP\ MESSAGE* ]]; then
            printf "%s" "$pgp_text" | gpg --batch -d --no-tty --use-agent
            in_pgp_section=false
            pgp_text=""
        fi
    done < "$file" > "$file.decrypted"
done

2 个答案:

答案 0 :(得分:0)

未测试

for file in *; do
    in_pgp_section=false
    pgp_text=""

    while read line; do
        if [[ $line == "-----BEGIN PGP MESSAGE-----" ]]; then
            in_pgp_section=true
        fi

        if ! $in_pgp_section; then
            echo "$line"
            continue
        fi

        pgp_text+="$line"$'\n'

        if [[ $line == "-----END PGP MESSAGE-----" ]]; then
            printf "%s" "$pgp_text" | gpg -d
            in_pgp_section=false
            pgp_text=""
        fi
    done < "$file" > "$file.decrypting"

    ln "$file" "$file.encrypted"  &&
    mv "$file.decrypting" "$file"
done

这应解密当前目录中所有文件的所有PGP部分,并保留原始文件的“.encrypted”扩展名

答案 1 :(得分:0)

这不是答案,而是朝着正确方向迈出的一步:

awk '/^-----BEGIN PGP MESSAGE-----$/{store=1;txt="";}
     {if(store==0){print}else{txt=txt"\n"$0}}
     /^-----END PGP MESSAGE-----$/{store=0;print tolower(txt)}' t.txt

/^-----BEGIN PGP MESSAGE-----$/{store=1;txt="";}当行匹配时,我们初始化变量txt并将标志store设置为1 / ^ ----- END PGP MESSAGE ----- $ / {store = 0; print txt}

每行

{if(store==0){print}else{txt=txt"\n"$0}},如果标志为0,我们打印该行,否则,我们将该行存储(追加)txt

/^-----END PGP MESSAGE-----$/{store=0;print tolower(txt)}当行匹配时,我们取消设置标志并执行有趣的部分(我只是以小写字母打印...)。那是你现在的工作。您可能需要调用system(“gpg”)并使用一些管道。祝你好运!