Shell POSIX OpenSSL file decryption script follow-up #1

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
1
down vote

favorite












This question is the first follow-up of: Shell POSIX OpenSSL file decryption script



Please read it before you continue reading this. Thank you.




I only have one new problem solved and I would like you to have a look.



That problem being accepting one option -o output_directory.



I have little idea if I did this the best way, but it works.



The code follows:




#!/bin/sh

bold=$(tput bold)
red=$(tput setaf 1)
yellow=$(tput setaf 3)
nocolor=$(tput sgr0)

bold_red=$bold$red
bold_yellow=$bold$yellow

print_usage_and_exit()

echo "Usage: $0 [-o output_directory] filename_to_decrypt"
exit 1


print_error_and_exit()

echo "$bold_red$1 Exit code = $2.$nocolor" 1>&2
exit "$2"


while getopts ":o:" option
do
case "$option" in
o)
given_output_directory=$OPTARG
;;
h | *)
print_usage_and_exit
;;
esac
done

shift $((OPTIND - 1))

[ "$#" -eq 0 ] &&
print_usage_and_exit

[ "$#" -gt 1 ] &&
print_error_and_exit "Multiple files are not supported." 2

[ ! -f "$1" ] &&
print_error_and_exit "The given argument is not an existing file." 3

input_filename="$1"

[ ! -r "$input_filename" ] &&
print_error_and_exit "Input file is not readable by you." 4

input_filepath=$(dirname "$input_filename")

if [ -z $given_output_directory ]
then
output_directory="$input_filepath"
else
output_directory="$given_output_directory"
fi

[ ! -w "$output_directory" ] &&
print_error_and_exit "Destination directory is not writable by you." 5

filename_extracted_from_path=$(basename "$input_filename")
filename_without_enc_extension="$filename_extracted_from_path%.enc"

if [ "$filename_extracted_from_path" = "$filename_without_enc_extension" ]
then
# the file has a different than .enc extension or no extension at all
# what we do now, is that we append .dec extention to the file name
output_filename="$output_directory/$filename_extracted_from_path".dec
else
# the file has the .enc extension
# what we do now, is that we use the file name without .enc extension
output_filename="$output_directory/$filename_without_enc_extension"
fi

[ -f "$output_filename" ] &&
print_error_and_exit "Destination file exists." 6

if ! pv -W "$input_filename" | openssl enc -aes-256-cbc -md sha256 -salt -out "$output_filename" -d 2> /dev/null
then
[ -f "$output_filename" ] && rm "$output_filename"

print_error_and_exit "Decryption failed." 7
else
echo "$bold_yellowDecryption successful.$nocolor"

exit 0
fi






share|improve this question



























    up vote
    1
    down vote

    favorite












    This question is the first follow-up of: Shell POSIX OpenSSL file decryption script



    Please read it before you continue reading this. Thank you.




    I only have one new problem solved and I would like you to have a look.



    That problem being accepting one option -o output_directory.



    I have little idea if I did this the best way, but it works.



    The code follows:




    #!/bin/sh

    bold=$(tput bold)
    red=$(tput setaf 1)
    yellow=$(tput setaf 3)
    nocolor=$(tput sgr0)

    bold_red=$bold$red
    bold_yellow=$bold$yellow

    print_usage_and_exit()

    echo "Usage: $0 [-o output_directory] filename_to_decrypt"
    exit 1


    print_error_and_exit()

    echo "$bold_red$1 Exit code = $2.$nocolor" 1>&2
    exit "$2"


    while getopts ":o:" option
    do
    case "$option" in
    o)
    given_output_directory=$OPTARG
    ;;
    h | *)
    print_usage_and_exit
    ;;
    esac
    done

    shift $((OPTIND - 1))

    [ "$#" -eq 0 ] &&
    print_usage_and_exit

    [ "$#" -gt 1 ] &&
    print_error_and_exit "Multiple files are not supported." 2

    [ ! -f "$1" ] &&
    print_error_and_exit "The given argument is not an existing file." 3

    input_filename="$1"

    [ ! -r "$input_filename" ] &&
    print_error_and_exit "Input file is not readable by you." 4

    input_filepath=$(dirname "$input_filename")

    if [ -z $given_output_directory ]
    then
    output_directory="$input_filepath"
    else
    output_directory="$given_output_directory"
    fi

    [ ! -w "$output_directory" ] &&
    print_error_and_exit "Destination directory is not writable by you." 5

    filename_extracted_from_path=$(basename "$input_filename")
    filename_without_enc_extension="$filename_extracted_from_path%.enc"

    if [ "$filename_extracted_from_path" = "$filename_without_enc_extension" ]
    then
    # the file has a different than .enc extension or no extension at all
    # what we do now, is that we append .dec extention to the file name
    output_filename="$output_directory/$filename_extracted_from_path".dec
    else
    # the file has the .enc extension
    # what we do now, is that we use the file name without .enc extension
    output_filename="$output_directory/$filename_without_enc_extension"
    fi

    [ -f "$output_filename" ] &&
    print_error_and_exit "Destination file exists." 6

    if ! pv -W "$input_filename" | openssl enc -aes-256-cbc -md sha256 -salt -out "$output_filename" -d 2> /dev/null
    then
    [ -f "$output_filename" ] && rm "$output_filename"

    print_error_and_exit "Decryption failed." 7
    else
    echo "$bold_yellowDecryption successful.$nocolor"

    exit 0
    fi






    share|improve this question























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      This question is the first follow-up of: Shell POSIX OpenSSL file decryption script



      Please read it before you continue reading this. Thank you.




      I only have one new problem solved and I would like you to have a look.



      That problem being accepting one option -o output_directory.



      I have little idea if I did this the best way, but it works.



      The code follows:




      #!/bin/sh

      bold=$(tput bold)
      red=$(tput setaf 1)
      yellow=$(tput setaf 3)
      nocolor=$(tput sgr0)

      bold_red=$bold$red
      bold_yellow=$bold$yellow

      print_usage_and_exit()

      echo "Usage: $0 [-o output_directory] filename_to_decrypt"
      exit 1


      print_error_and_exit()

      echo "$bold_red$1 Exit code = $2.$nocolor" 1>&2
      exit "$2"


      while getopts ":o:" option
      do
      case "$option" in
      o)
      given_output_directory=$OPTARG
      ;;
      h | *)
      print_usage_and_exit
      ;;
      esac
      done

      shift $((OPTIND - 1))

      [ "$#" -eq 0 ] &&
      print_usage_and_exit

      [ "$#" -gt 1 ] &&
      print_error_and_exit "Multiple files are not supported." 2

      [ ! -f "$1" ] &&
      print_error_and_exit "The given argument is not an existing file." 3

      input_filename="$1"

      [ ! -r "$input_filename" ] &&
      print_error_and_exit "Input file is not readable by you." 4

      input_filepath=$(dirname "$input_filename")

      if [ -z $given_output_directory ]
      then
      output_directory="$input_filepath"
      else
      output_directory="$given_output_directory"
      fi

      [ ! -w "$output_directory" ] &&
      print_error_and_exit "Destination directory is not writable by you." 5

      filename_extracted_from_path=$(basename "$input_filename")
      filename_without_enc_extension="$filename_extracted_from_path%.enc"

      if [ "$filename_extracted_from_path" = "$filename_without_enc_extension" ]
      then
      # the file has a different than .enc extension or no extension at all
      # what we do now, is that we append .dec extention to the file name
      output_filename="$output_directory/$filename_extracted_from_path".dec
      else
      # the file has the .enc extension
      # what we do now, is that we use the file name without .enc extension
      output_filename="$output_directory/$filename_without_enc_extension"
      fi

      [ -f "$output_filename" ] &&
      print_error_and_exit "Destination file exists." 6

      if ! pv -W "$input_filename" | openssl enc -aes-256-cbc -md sha256 -salt -out "$output_filename" -d 2> /dev/null
      then
      [ -f "$output_filename" ] && rm "$output_filename"

      print_error_and_exit "Decryption failed." 7
      else
      echo "$bold_yellowDecryption successful.$nocolor"

      exit 0
      fi






      share|improve this question













      This question is the first follow-up of: Shell POSIX OpenSSL file decryption script



      Please read it before you continue reading this. Thank you.




      I only have one new problem solved and I would like you to have a look.



      That problem being accepting one option -o output_directory.



      I have little idea if I did this the best way, but it works.



      The code follows:




      #!/bin/sh

      bold=$(tput bold)
      red=$(tput setaf 1)
      yellow=$(tput setaf 3)
      nocolor=$(tput sgr0)

      bold_red=$bold$red
      bold_yellow=$bold$yellow

      print_usage_and_exit()

      echo "Usage: $0 [-o output_directory] filename_to_decrypt"
      exit 1


      print_error_and_exit()

      echo "$bold_red$1 Exit code = $2.$nocolor" 1>&2
      exit "$2"


      while getopts ":o:" option
      do
      case "$option" in
      o)
      given_output_directory=$OPTARG
      ;;
      h | *)
      print_usage_and_exit
      ;;
      esac
      done

      shift $((OPTIND - 1))

      [ "$#" -eq 0 ] &&
      print_usage_and_exit

      [ "$#" -gt 1 ] &&
      print_error_and_exit "Multiple files are not supported." 2

      [ ! -f "$1" ] &&
      print_error_and_exit "The given argument is not an existing file." 3

      input_filename="$1"

      [ ! -r "$input_filename" ] &&
      print_error_and_exit "Input file is not readable by you." 4

      input_filepath=$(dirname "$input_filename")

      if [ -z $given_output_directory ]
      then
      output_directory="$input_filepath"
      else
      output_directory="$given_output_directory"
      fi

      [ ! -w "$output_directory" ] &&
      print_error_and_exit "Destination directory is not writable by you." 5

      filename_extracted_from_path=$(basename "$input_filename")
      filename_without_enc_extension="$filename_extracted_from_path%.enc"

      if [ "$filename_extracted_from_path" = "$filename_without_enc_extension" ]
      then
      # the file has a different than .enc extension or no extension at all
      # what we do now, is that we append .dec extention to the file name
      output_filename="$output_directory/$filename_extracted_from_path".dec
      else
      # the file has the .enc extension
      # what we do now, is that we use the file name without .enc extension
      output_filename="$output_directory/$filename_without_enc_extension"
      fi

      [ -f "$output_filename" ] &&
      print_error_and_exit "Destination file exists." 6

      if ! pv -W "$input_filename" | openssl enc -aes-256-cbc -md sha256 -salt -out "$output_filename" -d 2> /dev/null
      then
      [ -f "$output_filename" ] && rm "$output_filename"

      print_error_and_exit "Decryption failed." 7
      else
      echo "$bold_yellowDecryption successful.$nocolor"

      exit 0
      fi








      share|improve this question












      share|improve this question




      share|improve this question








      edited Jun 19 at 17:46









      200_success

      123k14143401




      123k14143401









      asked Jan 18 at 6:02









      Vlastimil

      519316




      519316




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          Although print_error_and_exit correctly sends output to standard error and exits with a non-zero status, print_usage_and_exit outputs to standard out. I recommend explicitly accepting -h (as your case implies, but getopts hasn't been instructed to do), and if the user asks for help, then writing to standard out and returning success, but if the help is provided due to error, then writing to standard error and returning failure:



          print_usage()

          echo "Usage: $0 [-o output_directory] filename_to_decrypt"


          while getopts ":ho:" option
          do
          case "$option" in
          o)
          given_output_directory=$OPTARG
          ;;
          h)
          print_usage
          exit 0
          ;;
          '?')
          print_usage >&2
          exit 1
          ;;
          esac
          done

          shift $((OPTIND - 1))

          [ "$#" -eq 0 ] &&
          print_usage && exit 1



          While we're on error reporting, you might want to consider making the exit code be the first argument to print_error_and_exit rather than the last. That can make the code easier to read, and it also allows you to pass multiple arguments, just like echo which it wraps:



          print_error_and_exit()

          value=$1; shift
          echo "$bold_red$* Exit code = $value.$nocolor" 1>&2
          exit "$value"




          It's good to see that you use tput to produce the terminal-specific escape codes (if they exist) for highlighting. But it's probably not worth putting them into variables for a single use each. I'd get rid of the variables and just write something like



          print_error_and_exit()

          value=$1; shift
          exec >&2
          tput bold
          tput setaf 1 # red
          echo "$* Exit code = $value."
          tput sgr0
          exit "$value"



          and (in the success branch)



          else
          tput bold
          tput setaf 3 # yellow
          echo "Decryption successful."
          tput sgr0

          exit 0
          fi



          These tests are probably over-doing it:



          [ ! -f "$1" ] &&
          print_error_and_exit 3 "The given argument is not an existing file."

          input_filename="$1"

          [ ! -r "$input_filename" ] &&
          print_error_and_exit 4 "Input file is not readable by you."


          Unless there's a good reason we can't accept input from a pipe or other non-regular file, just skip the -f test: -r will fail if its argument doesn't exist. It's also worth including the filename in the message - this is really useful when the user expands a variable into the call, and it doesn't expand to what she expects:



          [ -r "$1" ] ||
          print_error_and_exit 3 "$1: not a readable file."


          If you really feel you need different exit status for non-existent and existing-but-unreadable files (why?), then consider -e as an alternative to -f.




          We should check whether the supplied output directory is actually a directory, before trying to use it:



          [ -d "$output_directory" ] ||
          print_error_and_exit 4 "$output_directory: not a directory."
          [ -w "$output_directory" ] ||
          print_error_and_exit 5 "Destination directory is not writeable by you."



          A shorter way to write this:



          if [ -z $given_output_directory ]
          then
          output_directory="$input_filepath"
          else
          output_directory="$given_output_directory"
          fi


          is to use parameter substitution with - modifier:



          output_directory="$given_output_directory:-$input_filepath"



          I think a case helps with matching filename patterns here:



          if [ "$filename_extracted_from_path" = "$filename_without_enc_extension" ]
          then


          I'd write that block as:



          filename_extracted_from_path=$(basename "$input_filename")

          # Strip .enc suffix from name if it has one, else add .dec suffix
          case "$filename_extracted_from_path" in
          *.enc)
          output_filename="$filename_extracted_from_path%.enc"
          ;;
          *)
          output_filename="$filename_extracted_from_path".dec
          ;;
          esac
          output_filename="$output_directory/$output_filename"


          Note that there's no longer a need for $filename_without_enc_extension.




          You definitely need to replace this -f with -e:



          [ -f "$output_filename" ] &&
          print_error_and_exit 6 "Destination file exists."





          share|improve this answer























            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185367%2fshell-posix-openssl-file-decryption-script-follow-up-1%23new-answer', 'question_page');

            );

            Post as a guest






























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            1
            down vote



            accepted










            Although print_error_and_exit correctly sends output to standard error and exits with a non-zero status, print_usage_and_exit outputs to standard out. I recommend explicitly accepting -h (as your case implies, but getopts hasn't been instructed to do), and if the user asks for help, then writing to standard out and returning success, but if the help is provided due to error, then writing to standard error and returning failure:



            print_usage()

            echo "Usage: $0 [-o output_directory] filename_to_decrypt"


            while getopts ":ho:" option
            do
            case "$option" in
            o)
            given_output_directory=$OPTARG
            ;;
            h)
            print_usage
            exit 0
            ;;
            '?')
            print_usage >&2
            exit 1
            ;;
            esac
            done

            shift $((OPTIND - 1))

            [ "$#" -eq 0 ] &&
            print_usage && exit 1



            While we're on error reporting, you might want to consider making the exit code be the first argument to print_error_and_exit rather than the last. That can make the code easier to read, and it also allows you to pass multiple arguments, just like echo which it wraps:



            print_error_and_exit()

            value=$1; shift
            echo "$bold_red$* Exit code = $value.$nocolor" 1>&2
            exit "$value"




            It's good to see that you use tput to produce the terminal-specific escape codes (if they exist) for highlighting. But it's probably not worth putting them into variables for a single use each. I'd get rid of the variables and just write something like



            print_error_and_exit()

            value=$1; shift
            exec >&2
            tput bold
            tput setaf 1 # red
            echo "$* Exit code = $value."
            tput sgr0
            exit "$value"



            and (in the success branch)



            else
            tput bold
            tput setaf 3 # yellow
            echo "Decryption successful."
            tput sgr0

            exit 0
            fi



            These tests are probably over-doing it:



            [ ! -f "$1" ] &&
            print_error_and_exit 3 "The given argument is not an existing file."

            input_filename="$1"

            [ ! -r "$input_filename" ] &&
            print_error_and_exit 4 "Input file is not readable by you."


            Unless there's a good reason we can't accept input from a pipe or other non-regular file, just skip the -f test: -r will fail if its argument doesn't exist. It's also worth including the filename in the message - this is really useful when the user expands a variable into the call, and it doesn't expand to what she expects:



            [ -r "$1" ] ||
            print_error_and_exit 3 "$1: not a readable file."


            If you really feel you need different exit status for non-existent and existing-but-unreadable files (why?), then consider -e as an alternative to -f.




            We should check whether the supplied output directory is actually a directory, before trying to use it:



            [ -d "$output_directory" ] ||
            print_error_and_exit 4 "$output_directory: not a directory."
            [ -w "$output_directory" ] ||
            print_error_and_exit 5 "Destination directory is not writeable by you."



            A shorter way to write this:



            if [ -z $given_output_directory ]
            then
            output_directory="$input_filepath"
            else
            output_directory="$given_output_directory"
            fi


            is to use parameter substitution with - modifier:



            output_directory="$given_output_directory:-$input_filepath"



            I think a case helps with matching filename patterns here:



            if [ "$filename_extracted_from_path" = "$filename_without_enc_extension" ]
            then


            I'd write that block as:



            filename_extracted_from_path=$(basename "$input_filename")

            # Strip .enc suffix from name if it has one, else add .dec suffix
            case "$filename_extracted_from_path" in
            *.enc)
            output_filename="$filename_extracted_from_path%.enc"
            ;;
            *)
            output_filename="$filename_extracted_from_path".dec
            ;;
            esac
            output_filename="$output_directory/$output_filename"


            Note that there's no longer a need for $filename_without_enc_extension.




            You definitely need to replace this -f with -e:



            [ -f "$output_filename" ] &&
            print_error_and_exit 6 "Destination file exists."





            share|improve this answer



























              up vote
              1
              down vote



              accepted










              Although print_error_and_exit correctly sends output to standard error and exits with a non-zero status, print_usage_and_exit outputs to standard out. I recommend explicitly accepting -h (as your case implies, but getopts hasn't been instructed to do), and if the user asks for help, then writing to standard out and returning success, but if the help is provided due to error, then writing to standard error and returning failure:



              print_usage()

              echo "Usage: $0 [-o output_directory] filename_to_decrypt"


              while getopts ":ho:" option
              do
              case "$option" in
              o)
              given_output_directory=$OPTARG
              ;;
              h)
              print_usage
              exit 0
              ;;
              '?')
              print_usage >&2
              exit 1
              ;;
              esac
              done

              shift $((OPTIND - 1))

              [ "$#" -eq 0 ] &&
              print_usage && exit 1



              While we're on error reporting, you might want to consider making the exit code be the first argument to print_error_and_exit rather than the last. That can make the code easier to read, and it also allows you to pass multiple arguments, just like echo which it wraps:



              print_error_and_exit()

              value=$1; shift
              echo "$bold_red$* Exit code = $value.$nocolor" 1>&2
              exit "$value"




              It's good to see that you use tput to produce the terminal-specific escape codes (if they exist) for highlighting. But it's probably not worth putting them into variables for a single use each. I'd get rid of the variables and just write something like



              print_error_and_exit()

              value=$1; shift
              exec >&2
              tput bold
              tput setaf 1 # red
              echo "$* Exit code = $value."
              tput sgr0
              exit "$value"



              and (in the success branch)



              else
              tput bold
              tput setaf 3 # yellow
              echo "Decryption successful."
              tput sgr0

              exit 0
              fi



              These tests are probably over-doing it:



              [ ! -f "$1" ] &&
              print_error_and_exit 3 "The given argument is not an existing file."

              input_filename="$1"

              [ ! -r "$input_filename" ] &&
              print_error_and_exit 4 "Input file is not readable by you."


              Unless there's a good reason we can't accept input from a pipe or other non-regular file, just skip the -f test: -r will fail if its argument doesn't exist. It's also worth including the filename in the message - this is really useful when the user expands a variable into the call, and it doesn't expand to what she expects:



              [ -r "$1" ] ||
              print_error_and_exit 3 "$1: not a readable file."


              If you really feel you need different exit status for non-existent and existing-but-unreadable files (why?), then consider -e as an alternative to -f.




              We should check whether the supplied output directory is actually a directory, before trying to use it:



              [ -d "$output_directory" ] ||
              print_error_and_exit 4 "$output_directory: not a directory."
              [ -w "$output_directory" ] ||
              print_error_and_exit 5 "Destination directory is not writeable by you."



              A shorter way to write this:



              if [ -z $given_output_directory ]
              then
              output_directory="$input_filepath"
              else
              output_directory="$given_output_directory"
              fi


              is to use parameter substitution with - modifier:



              output_directory="$given_output_directory:-$input_filepath"



              I think a case helps with matching filename patterns here:



              if [ "$filename_extracted_from_path" = "$filename_without_enc_extension" ]
              then


              I'd write that block as:



              filename_extracted_from_path=$(basename "$input_filename")

              # Strip .enc suffix from name if it has one, else add .dec suffix
              case "$filename_extracted_from_path" in
              *.enc)
              output_filename="$filename_extracted_from_path%.enc"
              ;;
              *)
              output_filename="$filename_extracted_from_path".dec
              ;;
              esac
              output_filename="$output_directory/$output_filename"


              Note that there's no longer a need for $filename_without_enc_extension.




              You definitely need to replace this -f with -e:



              [ -f "$output_filename" ] &&
              print_error_and_exit 6 "Destination file exists."





              share|improve this answer

























                up vote
                1
                down vote



                accepted







                up vote
                1
                down vote



                accepted






                Although print_error_and_exit correctly sends output to standard error and exits with a non-zero status, print_usage_and_exit outputs to standard out. I recommend explicitly accepting -h (as your case implies, but getopts hasn't been instructed to do), and if the user asks for help, then writing to standard out and returning success, but if the help is provided due to error, then writing to standard error and returning failure:



                print_usage()

                echo "Usage: $0 [-o output_directory] filename_to_decrypt"


                while getopts ":ho:" option
                do
                case "$option" in
                o)
                given_output_directory=$OPTARG
                ;;
                h)
                print_usage
                exit 0
                ;;
                '?')
                print_usage >&2
                exit 1
                ;;
                esac
                done

                shift $((OPTIND - 1))

                [ "$#" -eq 0 ] &&
                print_usage && exit 1



                While we're on error reporting, you might want to consider making the exit code be the first argument to print_error_and_exit rather than the last. That can make the code easier to read, and it also allows you to pass multiple arguments, just like echo which it wraps:



                print_error_and_exit()

                value=$1; shift
                echo "$bold_red$* Exit code = $value.$nocolor" 1>&2
                exit "$value"




                It's good to see that you use tput to produce the terminal-specific escape codes (if they exist) for highlighting. But it's probably not worth putting them into variables for a single use each. I'd get rid of the variables and just write something like



                print_error_and_exit()

                value=$1; shift
                exec >&2
                tput bold
                tput setaf 1 # red
                echo "$* Exit code = $value."
                tput sgr0
                exit "$value"



                and (in the success branch)



                else
                tput bold
                tput setaf 3 # yellow
                echo "Decryption successful."
                tput sgr0

                exit 0
                fi



                These tests are probably over-doing it:



                [ ! -f "$1" ] &&
                print_error_and_exit 3 "The given argument is not an existing file."

                input_filename="$1"

                [ ! -r "$input_filename" ] &&
                print_error_and_exit 4 "Input file is not readable by you."


                Unless there's a good reason we can't accept input from a pipe or other non-regular file, just skip the -f test: -r will fail if its argument doesn't exist. It's also worth including the filename in the message - this is really useful when the user expands a variable into the call, and it doesn't expand to what she expects:



                [ -r "$1" ] ||
                print_error_and_exit 3 "$1: not a readable file."


                If you really feel you need different exit status for non-existent and existing-but-unreadable files (why?), then consider -e as an alternative to -f.




                We should check whether the supplied output directory is actually a directory, before trying to use it:



                [ -d "$output_directory" ] ||
                print_error_and_exit 4 "$output_directory: not a directory."
                [ -w "$output_directory" ] ||
                print_error_and_exit 5 "Destination directory is not writeable by you."



                A shorter way to write this:



                if [ -z $given_output_directory ]
                then
                output_directory="$input_filepath"
                else
                output_directory="$given_output_directory"
                fi


                is to use parameter substitution with - modifier:



                output_directory="$given_output_directory:-$input_filepath"



                I think a case helps with matching filename patterns here:



                if [ "$filename_extracted_from_path" = "$filename_without_enc_extension" ]
                then


                I'd write that block as:



                filename_extracted_from_path=$(basename "$input_filename")

                # Strip .enc suffix from name if it has one, else add .dec suffix
                case "$filename_extracted_from_path" in
                *.enc)
                output_filename="$filename_extracted_from_path%.enc"
                ;;
                *)
                output_filename="$filename_extracted_from_path".dec
                ;;
                esac
                output_filename="$output_directory/$output_filename"


                Note that there's no longer a need for $filename_without_enc_extension.




                You definitely need to replace this -f with -e:



                [ -f "$output_filename" ] &&
                print_error_and_exit 6 "Destination file exists."





                share|improve this answer















                Although print_error_and_exit correctly sends output to standard error and exits with a non-zero status, print_usage_and_exit outputs to standard out. I recommend explicitly accepting -h (as your case implies, but getopts hasn't been instructed to do), and if the user asks for help, then writing to standard out and returning success, but if the help is provided due to error, then writing to standard error and returning failure:



                print_usage()

                echo "Usage: $0 [-o output_directory] filename_to_decrypt"


                while getopts ":ho:" option
                do
                case "$option" in
                o)
                given_output_directory=$OPTARG
                ;;
                h)
                print_usage
                exit 0
                ;;
                '?')
                print_usage >&2
                exit 1
                ;;
                esac
                done

                shift $((OPTIND - 1))

                [ "$#" -eq 0 ] &&
                print_usage && exit 1



                While we're on error reporting, you might want to consider making the exit code be the first argument to print_error_and_exit rather than the last. That can make the code easier to read, and it also allows you to pass multiple arguments, just like echo which it wraps:



                print_error_and_exit()

                value=$1; shift
                echo "$bold_red$* Exit code = $value.$nocolor" 1>&2
                exit "$value"




                It's good to see that you use tput to produce the terminal-specific escape codes (if they exist) for highlighting. But it's probably not worth putting them into variables for a single use each. I'd get rid of the variables and just write something like



                print_error_and_exit()

                value=$1; shift
                exec >&2
                tput bold
                tput setaf 1 # red
                echo "$* Exit code = $value."
                tput sgr0
                exit "$value"



                and (in the success branch)



                else
                tput bold
                tput setaf 3 # yellow
                echo "Decryption successful."
                tput sgr0

                exit 0
                fi



                These tests are probably over-doing it:



                [ ! -f "$1" ] &&
                print_error_and_exit 3 "The given argument is not an existing file."

                input_filename="$1"

                [ ! -r "$input_filename" ] &&
                print_error_and_exit 4 "Input file is not readable by you."


                Unless there's a good reason we can't accept input from a pipe or other non-regular file, just skip the -f test: -r will fail if its argument doesn't exist. It's also worth including the filename in the message - this is really useful when the user expands a variable into the call, and it doesn't expand to what she expects:



                [ -r "$1" ] ||
                print_error_and_exit 3 "$1: not a readable file."


                If you really feel you need different exit status for non-existent and existing-but-unreadable files (why?), then consider -e as an alternative to -f.




                We should check whether the supplied output directory is actually a directory, before trying to use it:



                [ -d "$output_directory" ] ||
                print_error_and_exit 4 "$output_directory: not a directory."
                [ -w "$output_directory" ] ||
                print_error_and_exit 5 "Destination directory is not writeable by you."



                A shorter way to write this:



                if [ -z $given_output_directory ]
                then
                output_directory="$input_filepath"
                else
                output_directory="$given_output_directory"
                fi


                is to use parameter substitution with - modifier:



                output_directory="$given_output_directory:-$input_filepath"



                I think a case helps with matching filename patterns here:



                if [ "$filename_extracted_from_path" = "$filename_without_enc_extension" ]
                then


                I'd write that block as:



                filename_extracted_from_path=$(basename "$input_filename")

                # Strip .enc suffix from name if it has one, else add .dec suffix
                case "$filename_extracted_from_path" in
                *.enc)
                output_filename="$filename_extracted_from_path%.enc"
                ;;
                *)
                output_filename="$filename_extracted_from_path".dec
                ;;
                esac
                output_filename="$output_directory/$output_filename"


                Note that there's no longer a need for $filename_without_enc_extension.




                You definitely need to replace this -f with -e:



                [ -f "$output_filename" ] &&
                print_error_and_exit 6 "Destination file exists."






                share|improve this answer















                share|improve this answer



                share|improve this answer








                edited Jun 19 at 9:11


























                answered Jun 19 at 8:31









                Toby Speight

                17.8k13491




                17.8k13491






















                     

                    draft saved


                    draft discarded


























                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185367%2fshell-posix-openssl-file-decryption-script-follow-up-1%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Popular posts from this blog

                    Chat program with C++ and SFML

                    Function to Return a JSON Like Objects Using VBA Collections and Arrays

                    Will my employers contract hold up in court?