Echo with obfuscation












14















I need to print some variables to the screen but I need to preferebly obfuscate the first few characters and I was wondering if there was an echo command in bash that can obfuscate the first characters of a secret value while printing it to the terminal:



echo 'secretvalue'
********lue









share|improve this question









New contributor




Xerxes is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

























    14















    I need to print some variables to the screen but I need to preferebly obfuscate the first few characters and I was wondering if there was an echo command in bash that can obfuscate the first characters of a secret value while printing it to the terminal:



    echo 'secretvalue'
    ********lue









    share|improve this question









    New contributor




    Xerxes is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.























      14












      14








      14


      1






      I need to print some variables to the screen but I need to preferebly obfuscate the first few characters and I was wondering if there was an echo command in bash that can obfuscate the first characters of a secret value while printing it to the terminal:



      echo 'secretvalue'
      ********lue









      share|improve this question









      New contributor




      Xerxes is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.












      I need to print some variables to the screen but I need to preferebly obfuscate the first few characters and I was wondering if there was an echo command in bash that can obfuscate the first characters of a secret value while printing it to the terminal:



      echo 'secretvalue'
      ********lue






      bash security






      share|improve this question









      New contributor




      Xerxes is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      Xerxes is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited Mar 20 at 14:16









      Jeff Schaller

      43.9k1161141




      43.9k1161141






      New contributor




      Xerxes is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked Mar 20 at 14:12









      XerxesXerxes

      1735




      1735




      New contributor




      Xerxes is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Xerxes is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Xerxes is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          6 Answers
          6






          active

          oldest

          votes


















          11














          The other answers mask a fixed amount of characters from the start, with the plaintext suffix varying in length. An alternative would be to leave a fixed amount of characters in plaintext, and to vary the length of the masked part. I don't know which one is more useful, but here's the other choice:



          #!/bin/bash
          mask() {
          local n=3 # number of chars to leave
          local a="${1:0:${#1}-n}" # take all but the last n chars
          local b="${1:${#1}-n}" # take the final n chars
          printf "%s%sn" "${a//?/*}" "$b" # substitute a with asterisks
          }

          mask abcde
          mask abcdefghijkl


          This prints **cde and *********jkl.





          If you like, you could also modify n for short strings to make sure a majority of the string gets masked. E.g. this would make sure at least three characters are masked even for short strings. (so abcde -> ***de, and abc -> ***):



          mask() {
          local n=3
          [[ ${#1} -le 5 ]] && n=$(( ${#1} - 3 ))
          local a="${1:0:${#1}-n}"
          local b="${1:${#1}-n}"
          printf "%s%sn" "${a//?/*}" "$b"
          }





          share|improve this answer

































            13














            One option would be to force yourself to use a function instead of echo, such as:



            obfuprint() {
            if [ "${#1}" -ge 8 ]
            then
            printf '%sn' "${1/????????/********}"
            else
            printf '%sn' "${1//?/*}"
            fi
            }


            Then you could call obfuprint 'secretvalue' and receive ********lue (with a trailing newline). The function uses parameter expansion to search for the first eight characters of the passed-in value and replaces them with eight asterisks. If the incoming value is shorter than eight characters, they are all replaced with asterisks. Thanks to ilkkachu for pointing out my initial assumption of eight-or-more character inputs!





            Inspired by ilkkachu's flexible masking answer, I thought it'd be interesting to add a variation that randomly masks some percentage of the string:



            obfuprintperc () {
            local perc=75 ## percent to obfuscate
            local i=0
            for((i=0; i < ${#1}; i++))
            do
            if [ $(( $RANDOM % 100 )) -lt "$perc" ]
            then
            printf '%s' '*'
            else
            printf '%s' "${1:i:1}"
            fi
            done
            echo
            }


            This relies on bash's $RANDOM special variable; it simply loops through each character of the input and decides whether to mask that character or print it. Sample output:



            $ obfuprintperc 0123456789
            0*****6*8*
            $ obfuprintperc 0123456789
            012***678*
            $ obfuprintperc 0123456789
            **********
            $ obfuprintperc 0123456789
            *****56***
            $ obfuprintperc 0123456789
            0*******8*





            share|improve this answer


























            • To be frank, I do not like random masking. A determined shoulder surfer will eventually get my secrets by pretending to like making small talk with me.

              – emory
              Mar 20 at 17:30











            • Certainly, displaying sensitive information should be done carefully! I presented random masking as an alternative to fixed-prefix masking and variable-prefix masking.

              – Jeff Schaller
              Mar 20 at 17:31






            • 4





              I am not a fan of fixed-prefix or variable-prefix masking either, but with those there exists a "kernel" of my secret that remains secret. With random masking, there is no "kernel". Eventually everything will be revealed to those patient enough.

              – emory
              Mar 20 at 17:35



















            7














            You could try piping to sed. For example, to replace the first 8 characters of a string with asterisks, you could pipe to the sed 's/^......../********/' command, e.g.:



            $ echo 'secretvalue' | sed 's/^......../********/'
            ********lue


            You can also define a function that does this:



            obsecho () { echo "$1" | sed 's/^......../*********/'; }





            share|improve this answer



















            • 2





              I'd suggest printf over echo so that you're not subject to interpreting data such as r or n

              – Jeff Schaller
              Mar 20 at 14:27











            • @JeffSchaller This is one of the reasons why I post on SE. Good point. Thanks for the feedback.

              – igal
              Mar 20 at 14:29











            • It's one of the many things I've learned in my time here, as well! Happy to pass it along!

              – Jeff Schaller
              Mar 20 at 14:30






            • 1





              No need to use a pipe when you can use a herestring instead: sed 's/^......../********/' <<< 'secretvalue'

              – wjandrea
              Mar 20 at 15:24













            • @roaima It's actually a temporary regular file. You can see it if you do bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.

              – JoL
              Mar 20 at 15:35





















            7














            A zsh variant that masks three quarters of the text:



            mask() printf '%sn' ${(l:$#1::*:)1:$#1*3/4}


            Example:



            $ mask secretvalue
            ********lue
            $ mask 12345678
            ******78
            $ mask 1234
            ***4


            To mask the first 8 chars:



            mask() printf '%sn' ${(l:$#1::*:)1:8}


            To mask all but the last 3 chars:



            mask() printf '%sn' ${(l:$#1::*:)1: -3}


            To mask a random number of characters:



            mask() printf '%sn' ${(l:$#1::*:)1: RANDOM%$#1}





            share|improve this answer

































              2














              Another option in Bash, if you don’t mind one simple eval you can do it with a couple of printf:



              # example data
              password=secretvalue
              chars_to_show=3

              # the real thing
              eval "printf '*%.0s' {1..$((${#password} - chars_to_show))}"
              printf '%sn' ${password: -chars_to_show}


              But be careful:




              • fix the above as you need when ${#password} is less than ${chars_to_show}

              • eval can be very dangerous with untrusted input: here it can be considered safe because its input comes only from safe sources, ie the length of ${password} and the value of ${chars_to_show}






              share|improve this answer










              New contributor




              LL3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
              Check out our Code of Conduct.




























                0














                Here's some toy Bash scripts to play with that show how to combine regex-like search with string substitution.



                strip_str.sh



                #!/usr/bin/env bash

                _str="${1}"
                _filter="${2:-'apl'}"
                echo "${_str//[${_filter}]/}"


                strip_str.sh 'apple-foo bar'
                # -> e-foo br
                strip_str.sh 'apple-foo bar' 'a'
                # -> pple-foo br


                privatize_str.sh



                #!/usr/bin/env bash

                _str="${1}"
                _filter="${2:-'apl'}"
                _replace="${3:-'*'}"
                echo "${_str//[${_filter}]/${_replace}}"


                privatize_str.sh 'apple-foo bar'
                # -> ****e-foo b*r


                restricted_str.sh



                #!/usr/bin/env bash

                _str="${1}"
                _valid="${2:-'a-z'}"
                _replace="${3:-''}"
                echo "${_str//[^${_valid}]/${_replace}}"


                restricted_str.sh 'apple-foo bar'
                # -> applefoobar




                Key takeaways





                • [a-z 0-9] is totally valid, and handy, as a <search> within ${_var_name//<search>/<replace>} for Bash


                • ^, within this context, is the reverse or not for regex-like searches

                • Built-ins are generally faster and often are more concise, especially when it cuts out unneeded piping



                While I get that printf is better in nearly all use cases the above code uses echo so as to not overly confuse what's going on.




                obfuscate_str.sh



                #!/usr/bin/env bash

                _str="${1}"
                _start="${2:-6}"
                _header="$(for i in {1..${_start}}; do echo -n '*'; done)"
                echo "${_header}${_str:${_start}}"


                obfuscate_str.sh 'apple-foo bar' 3
                # -> ***le-foo bar





                share|improve this answer

























                  Your Answer








                  StackExchange.ready(function() {
                  var channelOptions = {
                  tags: "".split(" "),
                  id: "106"
                  };
                  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',
                  autoActivateHeartbeat: false,
                  convertImagesToLinks: false,
                  noModals: true,
                  showLowRepImageUploadWarning: true,
                  reputationToPostImages: null,
                  bindNavPrevention: true,
                  postfix: "",
                  imageUploader: {
                  brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                  contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                  allowUrls: true
                  },
                  onDemand: true,
                  discardSelector: ".discard-answer"
                  ,immediatelyShowMarkdownHelp:true
                  });


                  }
                  });






                  Xerxes is a new contributor. Be nice, and check out our Code of Conduct.










                  draft saved

                  draft discarded


















                  StackExchange.ready(
                  function () {
                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f507450%2fecho-with-obfuscation%23new-answer', 'question_page');
                  }
                  );

                  Post as a guest















                  Required, but never shown

























                  6 Answers
                  6






                  active

                  oldest

                  votes








                  6 Answers
                  6






                  active

                  oldest

                  votes









                  active

                  oldest

                  votes






                  active

                  oldest

                  votes









                  11














                  The other answers mask a fixed amount of characters from the start, with the plaintext suffix varying in length. An alternative would be to leave a fixed amount of characters in plaintext, and to vary the length of the masked part. I don't know which one is more useful, but here's the other choice:



                  #!/bin/bash
                  mask() {
                  local n=3 # number of chars to leave
                  local a="${1:0:${#1}-n}" # take all but the last n chars
                  local b="${1:${#1}-n}" # take the final n chars
                  printf "%s%sn" "${a//?/*}" "$b" # substitute a with asterisks
                  }

                  mask abcde
                  mask abcdefghijkl


                  This prints **cde and *********jkl.





                  If you like, you could also modify n for short strings to make sure a majority of the string gets masked. E.g. this would make sure at least three characters are masked even for short strings. (so abcde -> ***de, and abc -> ***):



                  mask() {
                  local n=3
                  [[ ${#1} -le 5 ]] && n=$(( ${#1} - 3 ))
                  local a="${1:0:${#1}-n}"
                  local b="${1:${#1}-n}"
                  printf "%s%sn" "${a//?/*}" "$b"
                  }





                  share|improve this answer






























                    11














                    The other answers mask a fixed amount of characters from the start, with the plaintext suffix varying in length. An alternative would be to leave a fixed amount of characters in plaintext, and to vary the length of the masked part. I don't know which one is more useful, but here's the other choice:



                    #!/bin/bash
                    mask() {
                    local n=3 # number of chars to leave
                    local a="${1:0:${#1}-n}" # take all but the last n chars
                    local b="${1:${#1}-n}" # take the final n chars
                    printf "%s%sn" "${a//?/*}" "$b" # substitute a with asterisks
                    }

                    mask abcde
                    mask abcdefghijkl


                    This prints **cde and *********jkl.





                    If you like, you could also modify n for short strings to make sure a majority of the string gets masked. E.g. this would make sure at least three characters are masked even for short strings. (so abcde -> ***de, and abc -> ***):



                    mask() {
                    local n=3
                    [[ ${#1} -le 5 ]] && n=$(( ${#1} - 3 ))
                    local a="${1:0:${#1}-n}"
                    local b="${1:${#1}-n}"
                    printf "%s%sn" "${a//?/*}" "$b"
                    }





                    share|improve this answer




























                      11












                      11








                      11







                      The other answers mask a fixed amount of characters from the start, with the plaintext suffix varying in length. An alternative would be to leave a fixed amount of characters in plaintext, and to vary the length of the masked part. I don't know which one is more useful, but here's the other choice:



                      #!/bin/bash
                      mask() {
                      local n=3 # number of chars to leave
                      local a="${1:0:${#1}-n}" # take all but the last n chars
                      local b="${1:${#1}-n}" # take the final n chars
                      printf "%s%sn" "${a//?/*}" "$b" # substitute a with asterisks
                      }

                      mask abcde
                      mask abcdefghijkl


                      This prints **cde and *********jkl.





                      If you like, you could also modify n for short strings to make sure a majority of the string gets masked. E.g. this would make sure at least three characters are masked even for short strings. (so abcde -> ***de, and abc -> ***):



                      mask() {
                      local n=3
                      [[ ${#1} -le 5 ]] && n=$(( ${#1} - 3 ))
                      local a="${1:0:${#1}-n}"
                      local b="${1:${#1}-n}"
                      printf "%s%sn" "${a//?/*}" "$b"
                      }





                      share|improve this answer















                      The other answers mask a fixed amount of characters from the start, with the plaintext suffix varying in length. An alternative would be to leave a fixed amount of characters in plaintext, and to vary the length of the masked part. I don't know which one is more useful, but here's the other choice:



                      #!/bin/bash
                      mask() {
                      local n=3 # number of chars to leave
                      local a="${1:0:${#1}-n}" # take all but the last n chars
                      local b="${1:${#1}-n}" # take the final n chars
                      printf "%s%sn" "${a//?/*}" "$b" # substitute a with asterisks
                      }

                      mask abcde
                      mask abcdefghijkl


                      This prints **cde and *********jkl.





                      If you like, you could also modify n for short strings to make sure a majority of the string gets masked. E.g. this would make sure at least three characters are masked even for short strings. (so abcde -> ***de, and abc -> ***):



                      mask() {
                      local n=3
                      [[ ${#1} -le 5 ]] && n=$(( ${#1} - 3 ))
                      local a="${1:0:${#1}-n}"
                      local b="${1:${#1}-n}"
                      printf "%s%sn" "${a//?/*}" "$b"
                      }






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Mar 20 at 15:57

























                      answered Mar 20 at 15:23









                      ilkkachuilkkachu

                      62.5k10103179




                      62.5k10103179

























                          13














                          One option would be to force yourself to use a function instead of echo, such as:



                          obfuprint() {
                          if [ "${#1}" -ge 8 ]
                          then
                          printf '%sn' "${1/????????/********}"
                          else
                          printf '%sn' "${1//?/*}"
                          fi
                          }


                          Then you could call obfuprint 'secretvalue' and receive ********lue (with a trailing newline). The function uses parameter expansion to search for the first eight characters of the passed-in value and replaces them with eight asterisks. If the incoming value is shorter than eight characters, they are all replaced with asterisks. Thanks to ilkkachu for pointing out my initial assumption of eight-or-more character inputs!





                          Inspired by ilkkachu's flexible masking answer, I thought it'd be interesting to add a variation that randomly masks some percentage of the string:



                          obfuprintperc () {
                          local perc=75 ## percent to obfuscate
                          local i=0
                          for((i=0; i < ${#1}; i++))
                          do
                          if [ $(( $RANDOM % 100 )) -lt "$perc" ]
                          then
                          printf '%s' '*'
                          else
                          printf '%s' "${1:i:1}"
                          fi
                          done
                          echo
                          }


                          This relies on bash's $RANDOM special variable; it simply loops through each character of the input and decides whether to mask that character or print it. Sample output:



                          $ obfuprintperc 0123456789
                          0*****6*8*
                          $ obfuprintperc 0123456789
                          012***678*
                          $ obfuprintperc 0123456789
                          **********
                          $ obfuprintperc 0123456789
                          *****56***
                          $ obfuprintperc 0123456789
                          0*******8*





                          share|improve this answer


























                          • To be frank, I do not like random masking. A determined shoulder surfer will eventually get my secrets by pretending to like making small talk with me.

                            – emory
                            Mar 20 at 17:30











                          • Certainly, displaying sensitive information should be done carefully! I presented random masking as an alternative to fixed-prefix masking and variable-prefix masking.

                            – Jeff Schaller
                            Mar 20 at 17:31






                          • 4





                            I am not a fan of fixed-prefix or variable-prefix masking either, but with those there exists a "kernel" of my secret that remains secret. With random masking, there is no "kernel". Eventually everything will be revealed to those patient enough.

                            – emory
                            Mar 20 at 17:35
















                          13














                          One option would be to force yourself to use a function instead of echo, such as:



                          obfuprint() {
                          if [ "${#1}" -ge 8 ]
                          then
                          printf '%sn' "${1/????????/********}"
                          else
                          printf '%sn' "${1//?/*}"
                          fi
                          }


                          Then you could call obfuprint 'secretvalue' and receive ********lue (with a trailing newline). The function uses parameter expansion to search for the first eight characters of the passed-in value and replaces them with eight asterisks. If the incoming value is shorter than eight characters, they are all replaced with asterisks. Thanks to ilkkachu for pointing out my initial assumption of eight-or-more character inputs!





                          Inspired by ilkkachu's flexible masking answer, I thought it'd be interesting to add a variation that randomly masks some percentage of the string:



                          obfuprintperc () {
                          local perc=75 ## percent to obfuscate
                          local i=0
                          for((i=0; i < ${#1}; i++))
                          do
                          if [ $(( $RANDOM % 100 )) -lt "$perc" ]
                          then
                          printf '%s' '*'
                          else
                          printf '%s' "${1:i:1}"
                          fi
                          done
                          echo
                          }


                          This relies on bash's $RANDOM special variable; it simply loops through each character of the input and decides whether to mask that character or print it. Sample output:



                          $ obfuprintperc 0123456789
                          0*****6*8*
                          $ obfuprintperc 0123456789
                          012***678*
                          $ obfuprintperc 0123456789
                          **********
                          $ obfuprintperc 0123456789
                          *****56***
                          $ obfuprintperc 0123456789
                          0*******8*





                          share|improve this answer


























                          • To be frank, I do not like random masking. A determined shoulder surfer will eventually get my secrets by pretending to like making small talk with me.

                            – emory
                            Mar 20 at 17:30











                          • Certainly, displaying sensitive information should be done carefully! I presented random masking as an alternative to fixed-prefix masking and variable-prefix masking.

                            – Jeff Schaller
                            Mar 20 at 17:31






                          • 4





                            I am not a fan of fixed-prefix or variable-prefix masking either, but with those there exists a "kernel" of my secret that remains secret. With random masking, there is no "kernel". Eventually everything will be revealed to those patient enough.

                            – emory
                            Mar 20 at 17:35














                          13












                          13








                          13







                          One option would be to force yourself to use a function instead of echo, such as:



                          obfuprint() {
                          if [ "${#1}" -ge 8 ]
                          then
                          printf '%sn' "${1/????????/********}"
                          else
                          printf '%sn' "${1//?/*}"
                          fi
                          }


                          Then you could call obfuprint 'secretvalue' and receive ********lue (with a trailing newline). The function uses parameter expansion to search for the first eight characters of the passed-in value and replaces them with eight asterisks. If the incoming value is shorter than eight characters, they are all replaced with asterisks. Thanks to ilkkachu for pointing out my initial assumption of eight-or-more character inputs!





                          Inspired by ilkkachu's flexible masking answer, I thought it'd be interesting to add a variation that randomly masks some percentage of the string:



                          obfuprintperc () {
                          local perc=75 ## percent to obfuscate
                          local i=0
                          for((i=0; i < ${#1}; i++))
                          do
                          if [ $(( $RANDOM % 100 )) -lt "$perc" ]
                          then
                          printf '%s' '*'
                          else
                          printf '%s' "${1:i:1}"
                          fi
                          done
                          echo
                          }


                          This relies on bash's $RANDOM special variable; it simply loops through each character of the input and decides whether to mask that character or print it. Sample output:



                          $ obfuprintperc 0123456789
                          0*****6*8*
                          $ obfuprintperc 0123456789
                          012***678*
                          $ obfuprintperc 0123456789
                          **********
                          $ obfuprintperc 0123456789
                          *****56***
                          $ obfuprintperc 0123456789
                          0*******8*





                          share|improve this answer















                          One option would be to force yourself to use a function instead of echo, such as:



                          obfuprint() {
                          if [ "${#1}" -ge 8 ]
                          then
                          printf '%sn' "${1/????????/********}"
                          else
                          printf '%sn' "${1//?/*}"
                          fi
                          }


                          Then you could call obfuprint 'secretvalue' and receive ********lue (with a trailing newline). The function uses parameter expansion to search for the first eight characters of the passed-in value and replaces them with eight asterisks. If the incoming value is shorter than eight characters, they are all replaced with asterisks. Thanks to ilkkachu for pointing out my initial assumption of eight-or-more character inputs!





                          Inspired by ilkkachu's flexible masking answer, I thought it'd be interesting to add a variation that randomly masks some percentage of the string:



                          obfuprintperc () {
                          local perc=75 ## percent to obfuscate
                          local i=0
                          for((i=0; i < ${#1}; i++))
                          do
                          if [ $(( $RANDOM % 100 )) -lt "$perc" ]
                          then
                          printf '%s' '*'
                          else
                          printf '%s' "${1:i:1}"
                          fi
                          done
                          echo
                          }


                          This relies on bash's $RANDOM special variable; it simply loops through each character of the input and decides whether to mask that character or print it. Sample output:



                          $ obfuprintperc 0123456789
                          0*****6*8*
                          $ obfuprintperc 0123456789
                          012***678*
                          $ obfuprintperc 0123456789
                          **********
                          $ obfuprintperc 0123456789
                          *****56***
                          $ obfuprintperc 0123456789
                          0*******8*






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Mar 20 at 16:11

























                          answered Mar 20 at 14:20









                          Jeff SchallerJeff Schaller

                          43.9k1161141




                          43.9k1161141













                          • To be frank, I do not like random masking. A determined shoulder surfer will eventually get my secrets by pretending to like making small talk with me.

                            – emory
                            Mar 20 at 17:30











                          • Certainly, displaying sensitive information should be done carefully! I presented random masking as an alternative to fixed-prefix masking and variable-prefix masking.

                            – Jeff Schaller
                            Mar 20 at 17:31






                          • 4





                            I am not a fan of fixed-prefix or variable-prefix masking either, but with those there exists a "kernel" of my secret that remains secret. With random masking, there is no "kernel". Eventually everything will be revealed to those patient enough.

                            – emory
                            Mar 20 at 17:35



















                          • To be frank, I do not like random masking. A determined shoulder surfer will eventually get my secrets by pretending to like making small talk with me.

                            – emory
                            Mar 20 at 17:30











                          • Certainly, displaying sensitive information should be done carefully! I presented random masking as an alternative to fixed-prefix masking and variable-prefix masking.

                            – Jeff Schaller
                            Mar 20 at 17:31






                          • 4





                            I am not a fan of fixed-prefix or variable-prefix masking either, but with those there exists a "kernel" of my secret that remains secret. With random masking, there is no "kernel". Eventually everything will be revealed to those patient enough.

                            – emory
                            Mar 20 at 17:35

















                          To be frank, I do not like random masking. A determined shoulder surfer will eventually get my secrets by pretending to like making small talk with me.

                          – emory
                          Mar 20 at 17:30





                          To be frank, I do not like random masking. A determined shoulder surfer will eventually get my secrets by pretending to like making small talk with me.

                          – emory
                          Mar 20 at 17:30













                          Certainly, displaying sensitive information should be done carefully! I presented random masking as an alternative to fixed-prefix masking and variable-prefix masking.

                          – Jeff Schaller
                          Mar 20 at 17:31





                          Certainly, displaying sensitive information should be done carefully! I presented random masking as an alternative to fixed-prefix masking and variable-prefix masking.

                          – Jeff Schaller
                          Mar 20 at 17:31




                          4




                          4





                          I am not a fan of fixed-prefix or variable-prefix masking either, but with those there exists a "kernel" of my secret that remains secret. With random masking, there is no "kernel". Eventually everything will be revealed to those patient enough.

                          – emory
                          Mar 20 at 17:35





                          I am not a fan of fixed-prefix or variable-prefix masking either, but with those there exists a "kernel" of my secret that remains secret. With random masking, there is no "kernel". Eventually everything will be revealed to those patient enough.

                          – emory
                          Mar 20 at 17:35











                          7














                          You could try piping to sed. For example, to replace the first 8 characters of a string with asterisks, you could pipe to the sed 's/^......../********/' command, e.g.:



                          $ echo 'secretvalue' | sed 's/^......../********/'
                          ********lue


                          You can also define a function that does this:



                          obsecho () { echo "$1" | sed 's/^......../*********/'; }





                          share|improve this answer



















                          • 2





                            I'd suggest printf over echo so that you're not subject to interpreting data such as r or n

                            – Jeff Schaller
                            Mar 20 at 14:27











                          • @JeffSchaller This is one of the reasons why I post on SE. Good point. Thanks for the feedback.

                            – igal
                            Mar 20 at 14:29











                          • It's one of the many things I've learned in my time here, as well! Happy to pass it along!

                            – Jeff Schaller
                            Mar 20 at 14:30






                          • 1





                            No need to use a pipe when you can use a herestring instead: sed 's/^......../********/' <<< 'secretvalue'

                            – wjandrea
                            Mar 20 at 15:24













                          • @roaima It's actually a temporary regular file. You can see it if you do bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.

                            – JoL
                            Mar 20 at 15:35


















                          7














                          You could try piping to sed. For example, to replace the first 8 characters of a string with asterisks, you could pipe to the sed 's/^......../********/' command, e.g.:



                          $ echo 'secretvalue' | sed 's/^......../********/'
                          ********lue


                          You can also define a function that does this:



                          obsecho () { echo "$1" | sed 's/^......../*********/'; }





                          share|improve this answer



















                          • 2





                            I'd suggest printf over echo so that you're not subject to interpreting data such as r or n

                            – Jeff Schaller
                            Mar 20 at 14:27











                          • @JeffSchaller This is one of the reasons why I post on SE. Good point. Thanks for the feedback.

                            – igal
                            Mar 20 at 14:29











                          • It's one of the many things I've learned in my time here, as well! Happy to pass it along!

                            – Jeff Schaller
                            Mar 20 at 14:30






                          • 1





                            No need to use a pipe when you can use a herestring instead: sed 's/^......../********/' <<< 'secretvalue'

                            – wjandrea
                            Mar 20 at 15:24













                          • @roaima It's actually a temporary regular file. You can see it if you do bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.

                            – JoL
                            Mar 20 at 15:35
















                          7












                          7








                          7







                          You could try piping to sed. For example, to replace the first 8 characters of a string with asterisks, you could pipe to the sed 's/^......../********/' command, e.g.:



                          $ echo 'secretvalue' | sed 's/^......../********/'
                          ********lue


                          You can also define a function that does this:



                          obsecho () { echo "$1" | sed 's/^......../*********/'; }





                          share|improve this answer













                          You could try piping to sed. For example, to replace the first 8 characters of a string with asterisks, you could pipe to the sed 's/^......../********/' command, e.g.:



                          $ echo 'secretvalue' | sed 's/^......../********/'
                          ********lue


                          You can also define a function that does this:



                          obsecho () { echo "$1" | sed 's/^......../*********/'; }






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Mar 20 at 14:21









                          igaligal

                          6,0461536




                          6,0461536








                          • 2





                            I'd suggest printf over echo so that you're not subject to interpreting data such as r or n

                            – Jeff Schaller
                            Mar 20 at 14:27











                          • @JeffSchaller This is one of the reasons why I post on SE. Good point. Thanks for the feedback.

                            – igal
                            Mar 20 at 14:29











                          • It's one of the many things I've learned in my time here, as well! Happy to pass it along!

                            – Jeff Schaller
                            Mar 20 at 14:30






                          • 1





                            No need to use a pipe when you can use a herestring instead: sed 's/^......../********/' <<< 'secretvalue'

                            – wjandrea
                            Mar 20 at 15:24













                          • @roaima It's actually a temporary regular file. You can see it if you do bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.

                            – JoL
                            Mar 20 at 15:35
















                          • 2





                            I'd suggest printf over echo so that you're not subject to interpreting data such as r or n

                            – Jeff Schaller
                            Mar 20 at 14:27











                          • @JeffSchaller This is one of the reasons why I post on SE. Good point. Thanks for the feedback.

                            – igal
                            Mar 20 at 14:29











                          • It's one of the many things I've learned in my time here, as well! Happy to pass it along!

                            – Jeff Schaller
                            Mar 20 at 14:30






                          • 1





                            No need to use a pipe when you can use a herestring instead: sed 's/^......../********/' <<< 'secretvalue'

                            – wjandrea
                            Mar 20 at 15:24













                          • @roaima It's actually a temporary regular file. You can see it if you do bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.

                            – JoL
                            Mar 20 at 15:35










                          2




                          2





                          I'd suggest printf over echo so that you're not subject to interpreting data such as r or n

                          – Jeff Schaller
                          Mar 20 at 14:27





                          I'd suggest printf over echo so that you're not subject to interpreting data such as r or n

                          – Jeff Schaller
                          Mar 20 at 14:27













                          @JeffSchaller This is one of the reasons why I post on SE. Good point. Thanks for the feedback.

                          – igal
                          Mar 20 at 14:29





                          @JeffSchaller This is one of the reasons why I post on SE. Good point. Thanks for the feedback.

                          – igal
                          Mar 20 at 14:29













                          It's one of the many things I've learned in my time here, as well! Happy to pass it along!

                          – Jeff Schaller
                          Mar 20 at 14:30





                          It's one of the many things I've learned in my time here, as well! Happy to pass it along!

                          – Jeff Schaller
                          Mar 20 at 14:30




                          1




                          1





                          No need to use a pipe when you can use a herestring instead: sed 's/^......../********/' <<< 'secretvalue'

                          – wjandrea
                          Mar 20 at 15:24







                          No need to use a pipe when you can use a herestring instead: sed 's/^......../********/' <<< 'secretvalue'

                          – wjandrea
                          Mar 20 at 15:24















                          @roaima It's actually a temporary regular file. You can see it if you do bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.

                          – JoL
                          Mar 20 at 15:35







                          @roaima It's actually a temporary regular file. You can see it if you do bash -c 'lsof -d0 -a -p $$ 2>/dev/null' <<< foo.

                          – JoL
                          Mar 20 at 15:35













                          7














                          A zsh variant that masks three quarters of the text:



                          mask() printf '%sn' ${(l:$#1::*:)1:$#1*3/4}


                          Example:



                          $ mask secretvalue
                          ********lue
                          $ mask 12345678
                          ******78
                          $ mask 1234
                          ***4


                          To mask the first 8 chars:



                          mask() printf '%sn' ${(l:$#1::*:)1:8}


                          To mask all but the last 3 chars:



                          mask() printf '%sn' ${(l:$#1::*:)1: -3}


                          To mask a random number of characters:



                          mask() printf '%sn' ${(l:$#1::*:)1: RANDOM%$#1}





                          share|improve this answer






























                            7














                            A zsh variant that masks three quarters of the text:



                            mask() printf '%sn' ${(l:$#1::*:)1:$#1*3/4}


                            Example:



                            $ mask secretvalue
                            ********lue
                            $ mask 12345678
                            ******78
                            $ mask 1234
                            ***4


                            To mask the first 8 chars:



                            mask() printf '%sn' ${(l:$#1::*:)1:8}


                            To mask all but the last 3 chars:



                            mask() printf '%sn' ${(l:$#1::*:)1: -3}


                            To mask a random number of characters:



                            mask() printf '%sn' ${(l:$#1::*:)1: RANDOM%$#1}





                            share|improve this answer




























                              7












                              7








                              7







                              A zsh variant that masks three quarters of the text:



                              mask() printf '%sn' ${(l:$#1::*:)1:$#1*3/4}


                              Example:



                              $ mask secretvalue
                              ********lue
                              $ mask 12345678
                              ******78
                              $ mask 1234
                              ***4


                              To mask the first 8 chars:



                              mask() printf '%sn' ${(l:$#1::*:)1:8}


                              To mask all but the last 3 chars:



                              mask() printf '%sn' ${(l:$#1::*:)1: -3}


                              To mask a random number of characters:



                              mask() printf '%sn' ${(l:$#1::*:)1: RANDOM%$#1}





                              share|improve this answer















                              A zsh variant that masks three quarters of the text:



                              mask() printf '%sn' ${(l:$#1::*:)1:$#1*3/4}


                              Example:



                              $ mask secretvalue
                              ********lue
                              $ mask 12345678
                              ******78
                              $ mask 1234
                              ***4


                              To mask the first 8 chars:



                              mask() printf '%sn' ${(l:$#1::*:)1:8}


                              To mask all but the last 3 chars:



                              mask() printf '%sn' ${(l:$#1::*:)1: -3}


                              To mask a random number of characters:



                              mask() printf '%sn' ${(l:$#1::*:)1: RANDOM%$#1}






                              share|improve this answer














                              share|improve this answer



                              share|improve this answer








                              edited Mar 21 at 14:27

























                              answered Mar 20 at 16:53









                              Stéphane ChazelasStéphane Chazelas

                              311k57587945




                              311k57587945























                                  2














                                  Another option in Bash, if you don’t mind one simple eval you can do it with a couple of printf:



                                  # example data
                                  password=secretvalue
                                  chars_to_show=3

                                  # the real thing
                                  eval "printf '*%.0s' {1..$((${#password} - chars_to_show))}"
                                  printf '%sn' ${password: -chars_to_show}


                                  But be careful:




                                  • fix the above as you need when ${#password} is less than ${chars_to_show}

                                  • eval can be very dangerous with untrusted input: here it can be considered safe because its input comes only from safe sources, ie the length of ${password} and the value of ${chars_to_show}






                                  share|improve this answer










                                  New contributor




                                  LL3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                  Check out our Code of Conduct.

























                                    2














                                    Another option in Bash, if you don’t mind one simple eval you can do it with a couple of printf:



                                    # example data
                                    password=secretvalue
                                    chars_to_show=3

                                    # the real thing
                                    eval "printf '*%.0s' {1..$((${#password} - chars_to_show))}"
                                    printf '%sn' ${password: -chars_to_show}


                                    But be careful:




                                    • fix the above as you need when ${#password} is less than ${chars_to_show}

                                    • eval can be very dangerous with untrusted input: here it can be considered safe because its input comes only from safe sources, ie the length of ${password} and the value of ${chars_to_show}






                                    share|improve this answer










                                    New contributor




                                    LL3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                    Check out our Code of Conduct.























                                      2












                                      2








                                      2







                                      Another option in Bash, if you don’t mind one simple eval you can do it with a couple of printf:



                                      # example data
                                      password=secretvalue
                                      chars_to_show=3

                                      # the real thing
                                      eval "printf '*%.0s' {1..$((${#password} - chars_to_show))}"
                                      printf '%sn' ${password: -chars_to_show}


                                      But be careful:




                                      • fix the above as you need when ${#password} is less than ${chars_to_show}

                                      • eval can be very dangerous with untrusted input: here it can be considered safe because its input comes only from safe sources, ie the length of ${password} and the value of ${chars_to_show}






                                      share|improve this answer










                                      New contributor




                                      LL3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.










                                      Another option in Bash, if you don’t mind one simple eval you can do it with a couple of printf:



                                      # example data
                                      password=secretvalue
                                      chars_to_show=3

                                      # the real thing
                                      eval "printf '*%.0s' {1..$((${#password} - chars_to_show))}"
                                      printf '%sn' ${password: -chars_to_show}


                                      But be careful:




                                      • fix the above as you need when ${#password} is less than ${chars_to_show}

                                      • eval can be very dangerous with untrusted input: here it can be considered safe because its input comes only from safe sources, ie the length of ${password} and the value of ${chars_to_show}







                                      share|improve this answer










                                      New contributor




                                      LL3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.









                                      share|improve this answer



                                      share|improve this answer








                                      edited Mar 21 at 10:45









                                      ilkkachu

                                      62.5k10103179




                                      62.5k10103179






                                      New contributor




                                      LL3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.









                                      answered Mar 20 at 21:58









                                      LL3LL3

                                      964




                                      964




                                      New contributor




                                      LL3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.





                                      New contributor





                                      LL3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.






                                      LL3 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                                      Check out our Code of Conduct.























                                          0














                                          Here's some toy Bash scripts to play with that show how to combine regex-like search with string substitution.



                                          strip_str.sh



                                          #!/usr/bin/env bash

                                          _str="${1}"
                                          _filter="${2:-'apl'}"
                                          echo "${_str//[${_filter}]/}"


                                          strip_str.sh 'apple-foo bar'
                                          # -> e-foo br
                                          strip_str.sh 'apple-foo bar' 'a'
                                          # -> pple-foo br


                                          privatize_str.sh



                                          #!/usr/bin/env bash

                                          _str="${1}"
                                          _filter="${2:-'apl'}"
                                          _replace="${3:-'*'}"
                                          echo "${_str//[${_filter}]/${_replace}}"


                                          privatize_str.sh 'apple-foo bar'
                                          # -> ****e-foo b*r


                                          restricted_str.sh



                                          #!/usr/bin/env bash

                                          _str="${1}"
                                          _valid="${2:-'a-z'}"
                                          _replace="${3:-''}"
                                          echo "${_str//[^${_valid}]/${_replace}}"


                                          restricted_str.sh 'apple-foo bar'
                                          # -> applefoobar




                                          Key takeaways





                                          • [a-z 0-9] is totally valid, and handy, as a <search> within ${_var_name//<search>/<replace>} for Bash


                                          • ^, within this context, is the reverse or not for regex-like searches

                                          • Built-ins are generally faster and often are more concise, especially when it cuts out unneeded piping



                                          While I get that printf is better in nearly all use cases the above code uses echo so as to not overly confuse what's going on.




                                          obfuscate_str.sh



                                          #!/usr/bin/env bash

                                          _str="${1}"
                                          _start="${2:-6}"
                                          _header="$(for i in {1..${_start}}; do echo -n '*'; done)"
                                          echo "${_header}${_str:${_start}}"


                                          obfuscate_str.sh 'apple-foo bar' 3
                                          # -> ***le-foo bar





                                          share|improve this answer






























                                            0














                                            Here's some toy Bash scripts to play with that show how to combine regex-like search with string substitution.



                                            strip_str.sh



                                            #!/usr/bin/env bash

                                            _str="${1}"
                                            _filter="${2:-'apl'}"
                                            echo "${_str//[${_filter}]/}"


                                            strip_str.sh 'apple-foo bar'
                                            # -> e-foo br
                                            strip_str.sh 'apple-foo bar' 'a'
                                            # -> pple-foo br


                                            privatize_str.sh



                                            #!/usr/bin/env bash

                                            _str="${1}"
                                            _filter="${2:-'apl'}"
                                            _replace="${3:-'*'}"
                                            echo "${_str//[${_filter}]/${_replace}}"


                                            privatize_str.sh 'apple-foo bar'
                                            # -> ****e-foo b*r


                                            restricted_str.sh



                                            #!/usr/bin/env bash

                                            _str="${1}"
                                            _valid="${2:-'a-z'}"
                                            _replace="${3:-''}"
                                            echo "${_str//[^${_valid}]/${_replace}}"


                                            restricted_str.sh 'apple-foo bar'
                                            # -> applefoobar




                                            Key takeaways





                                            • [a-z 0-9] is totally valid, and handy, as a <search> within ${_var_name//<search>/<replace>} for Bash


                                            • ^, within this context, is the reverse or not for regex-like searches

                                            • Built-ins are generally faster and often are more concise, especially when it cuts out unneeded piping



                                            While I get that printf is better in nearly all use cases the above code uses echo so as to not overly confuse what's going on.




                                            obfuscate_str.sh



                                            #!/usr/bin/env bash

                                            _str="${1}"
                                            _start="${2:-6}"
                                            _header="$(for i in {1..${_start}}; do echo -n '*'; done)"
                                            echo "${_header}${_str:${_start}}"


                                            obfuscate_str.sh 'apple-foo bar' 3
                                            # -> ***le-foo bar





                                            share|improve this answer




























                                              0












                                              0








                                              0







                                              Here's some toy Bash scripts to play with that show how to combine regex-like search with string substitution.



                                              strip_str.sh



                                              #!/usr/bin/env bash

                                              _str="${1}"
                                              _filter="${2:-'apl'}"
                                              echo "${_str//[${_filter}]/}"


                                              strip_str.sh 'apple-foo bar'
                                              # -> e-foo br
                                              strip_str.sh 'apple-foo bar' 'a'
                                              # -> pple-foo br


                                              privatize_str.sh



                                              #!/usr/bin/env bash

                                              _str="${1}"
                                              _filter="${2:-'apl'}"
                                              _replace="${3:-'*'}"
                                              echo "${_str//[${_filter}]/${_replace}}"


                                              privatize_str.sh 'apple-foo bar'
                                              # -> ****e-foo b*r


                                              restricted_str.sh



                                              #!/usr/bin/env bash

                                              _str="${1}"
                                              _valid="${2:-'a-z'}"
                                              _replace="${3:-''}"
                                              echo "${_str//[^${_valid}]/${_replace}}"


                                              restricted_str.sh 'apple-foo bar'
                                              # -> applefoobar




                                              Key takeaways





                                              • [a-z 0-9] is totally valid, and handy, as a <search> within ${_var_name//<search>/<replace>} for Bash


                                              • ^, within this context, is the reverse or not for regex-like searches

                                              • Built-ins are generally faster and often are more concise, especially when it cuts out unneeded piping



                                              While I get that printf is better in nearly all use cases the above code uses echo so as to not overly confuse what's going on.




                                              obfuscate_str.sh



                                              #!/usr/bin/env bash

                                              _str="${1}"
                                              _start="${2:-6}"
                                              _header="$(for i in {1..${_start}}; do echo -n '*'; done)"
                                              echo "${_header}${_str:${_start}}"


                                              obfuscate_str.sh 'apple-foo bar' 3
                                              # -> ***le-foo bar





                                              share|improve this answer















                                              Here's some toy Bash scripts to play with that show how to combine regex-like search with string substitution.



                                              strip_str.sh



                                              #!/usr/bin/env bash

                                              _str="${1}"
                                              _filter="${2:-'apl'}"
                                              echo "${_str//[${_filter}]/}"


                                              strip_str.sh 'apple-foo bar'
                                              # -> e-foo br
                                              strip_str.sh 'apple-foo bar' 'a'
                                              # -> pple-foo br


                                              privatize_str.sh



                                              #!/usr/bin/env bash

                                              _str="${1}"
                                              _filter="${2:-'apl'}"
                                              _replace="${3:-'*'}"
                                              echo "${_str//[${_filter}]/${_replace}}"


                                              privatize_str.sh 'apple-foo bar'
                                              # -> ****e-foo b*r


                                              restricted_str.sh



                                              #!/usr/bin/env bash

                                              _str="${1}"
                                              _valid="${2:-'a-z'}"
                                              _replace="${3:-''}"
                                              echo "${_str//[^${_valid}]/${_replace}}"


                                              restricted_str.sh 'apple-foo bar'
                                              # -> applefoobar




                                              Key takeaways





                                              • [a-z 0-9] is totally valid, and handy, as a <search> within ${_var_name//<search>/<replace>} for Bash


                                              • ^, within this context, is the reverse or not for regex-like searches

                                              • Built-ins are generally faster and often are more concise, especially when it cuts out unneeded piping



                                              While I get that printf is better in nearly all use cases the above code uses echo so as to not overly confuse what's going on.




                                              obfuscate_str.sh



                                              #!/usr/bin/env bash

                                              _str="${1}"
                                              _start="${2:-6}"
                                              _header="$(for i in {1..${_start}}; do echo -n '*'; done)"
                                              echo "${_header}${_str:${_start}}"


                                              obfuscate_str.sh 'apple-foo bar' 3
                                              # -> ***le-foo bar






                                              share|improve this answer














                                              share|improve this answer



                                              share|improve this answer








                                              edited Mar 21 at 23:32

























                                              answered Mar 21 at 23:23









                                              S0AndS0S0AndS0

                                              1867




                                              1867






















                                                  Xerxes is a new contributor. Be nice, and check out our Code of Conduct.










                                                  draft saved

                                                  draft discarded


















                                                  Xerxes is a new contributor. Be nice, and check out our Code of Conduct.













                                                  Xerxes is a new contributor. Be nice, and check out our Code of Conduct.












                                                  Xerxes is a new contributor. Be nice, and check out our Code of Conduct.
















                                                  Thanks for contributing an answer to Unix & Linux Stack Exchange!


                                                  • Please be sure to answer the question. Provide details and share your research!

                                                  But avoid



                                                  • Asking for help, clarification, or responding to other answers.

                                                  • Making statements based on opinion; back them up with references or personal experience.


                                                  To learn more, see our tips on writing great answers.




                                                  draft saved


                                                  draft discarded














                                                  StackExchange.ready(
                                                  function () {
                                                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f507450%2fecho-with-obfuscation%23new-answer', 'question_page');
                                                  }
                                                  );

                                                  Post as a guest















                                                  Required, but never shown





















































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown

































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown







                                                  Popular posts from this blog

                                                  If I really need a card on my start hand, how many mulligans make sense? [duplicate]

                                                  Alcedinidae

                                                  Can an atomic nucleus contain both particles and antiparticles? [duplicate]