Search code examples
bashgnupg

Bash stdin - I'm losing all newline characters


I have this bash script to do encryption:

#!/bin/bash
#encrypt.sh

fn=$1
if [ $# -eq 0 ]
  then
    echo "Filename required..."
fi

echo "Type text. Hit Ctrl-d when done"
keyvariable=$(cat)

echo -e $keyvariable | gpg --symmetric --cipher-algo AES256 > $fn

And I have this script to do decryption:

#!/bin/bash
#decrypt.sh

fn=$1
if [ $# -eq 0 ]
  then
    echo "Filename required..."
fi

cat $fn | gpg --decrypt

Example:

sh encrypt.sh test

Type text. Hit Ctrl-d when done
hello

how

are




you

?

I enter the password and confirm it. OK great. I now have an encrypted file called "test".

But when I go to decrypt "test", here's the output:

sh decrypt test

gpg: AES256 encrypted data
gpg: encrypted with 1 passphrase
-e hello how are you ?

I'm losing all the newline characters! What to do?


Answer is quite simple actually:

echo -e "$keyvariable" | gpg --symmetric --cipher-algo AES256 > $fn

Note the quotes around $keyvariable.

That's it!


Solution

  • In this line

    echo -e $keyvariable | gpg --symmetric --cipher-algo AES256 > $fn
    

    when $keyvariable is expanded, any embedded whitespace (not just newlines) are used to split the resulting string into a number of distinct words. echo then outputs each word to standard output, separated by a single space. Newlines are just the most obvious "victims"; you might observe tabs (0x09) being replaced by spaces, as well as multiple runs of whitespace being reduced to a single space. There are other characters that may change as well, due to filename generation (the details of which are unimportant here).

    The solution is to quote the parameter expansion:

    echo -e "$keyvariable" | gpg --symmetric -cipher-algo AES256 > "$fn"
    

    As others have mentioned, it's simpler to allow gpg to read from standard input directly, instead of using cat to intercept the keystrokes and placing them in a variable.

    echo "Type text. Hit Ctrl-d when done"
    gpg --symmetric --cipher-algo AES256 > "$fn"
    

    (Actually, gpg may behave slightly differently when it is reading directly from the terminal, as shown here, versus reading from a pipe, as when you read from the echo command. That could explain your being prompted for a password. I think the solution is to tell gpg to read from standard input specifically by adding "-" as a final argument, but consult your man page to verify. That is,

    gpg --symmetric --cipher-algo AES256 - > "$fn"
    

    )