How to allow only certain characters in a bash variable





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







4















I want to prompt the user to input a URL, but it can only contain A-Z, a-z, 0-9, &, ., /, =, _, -, :, and ?.



So, for example:



Enter URL:
$ http://youtube.com/watch?v=1234df_AQ-x
That URL is allowed.

Enter URL:
$ https://unix.stackexchange.com/$FAKEurl%🍺123
That URL is NOT allowed.


This is what I've come up with so far, but it doesn't seem to work correctly:



if [[ ! "${URL}" == *[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_/&?:.=]* ]]; then
echo "That URL is NOT allowed."
else
echo "That URL is allowed."
fi


Please note that the URLs I provided in the example are just examples. 
This script needs to work with all possible user input; it just can't contain characters other than the ones I specified earlier.



Using bash 3.2.57(1)-release under macOS High Sierra 10.13.6.










share|improve this question































    4















    I want to prompt the user to input a URL, but it can only contain A-Z, a-z, 0-9, &, ., /, =, _, -, :, and ?.



    So, for example:



    Enter URL:
    $ http://youtube.com/watch?v=1234df_AQ-x
    That URL is allowed.

    Enter URL:
    $ https://unix.stackexchange.com/$FAKEurl%🍺123
    That URL is NOT allowed.


    This is what I've come up with so far, but it doesn't seem to work correctly:



    if [[ ! "${URL}" == *[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_/&?:.=]* ]]; then
    echo "That URL is NOT allowed."
    else
    echo "That URL is allowed."
    fi


    Please note that the URLs I provided in the example are just examples. 
    This script needs to work with all possible user input; it just can't contain characters other than the ones I specified earlier.



    Using bash 3.2.57(1)-release under macOS High Sierra 10.13.6.










    share|improve this question



























      4












      4








      4


      0






      I want to prompt the user to input a URL, but it can only contain A-Z, a-z, 0-9, &, ., /, =, _, -, :, and ?.



      So, for example:



      Enter URL:
      $ http://youtube.com/watch?v=1234df_AQ-x
      That URL is allowed.

      Enter URL:
      $ https://unix.stackexchange.com/$FAKEurl%🍺123
      That URL is NOT allowed.


      This is what I've come up with so far, but it doesn't seem to work correctly:



      if [[ ! "${URL}" == *[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_/&?:.=]* ]]; then
      echo "That URL is NOT allowed."
      else
      echo "That URL is allowed."
      fi


      Please note that the URLs I provided in the example are just examples. 
      This script needs to work with all possible user input; it just can't contain characters other than the ones I specified earlier.



      Using bash 3.2.57(1)-release under macOS High Sierra 10.13.6.










      share|improve this question
















      I want to prompt the user to input a URL, but it can only contain A-Z, a-z, 0-9, &, ., /, =, _, -, :, and ?.



      So, for example:



      Enter URL:
      $ http://youtube.com/watch?v=1234df_AQ-x
      That URL is allowed.

      Enter URL:
      $ https://unix.stackexchange.com/$FAKEurl%🍺123
      That URL is NOT allowed.


      This is what I've come up with so far, but it doesn't seem to work correctly:



      if [[ ! "${URL}" == *[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_/&?:.=]* ]]; then
      echo "That URL is NOT allowed."
      else
      echo "That URL is allowed."
      fi


      Please note that the URLs I provided in the example are just examples. 
      This script needs to work with all possible user input; it just can't contain characters other than the ones I specified earlier.



      Using bash 3.2.57(1)-release under macOS High Sierra 10.13.6.







      bash text-processing osx variable






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Feb 5 at 4:23









      G-Man

      13.7k93870




      13.7k93870










      asked Feb 5 at 0:36









      leetbacoonleetbacoon

      285




      285






















          4 Answers
          4






          active

          oldest

          votes


















          6














          You were close.



          You want to check whether the URL contains at least one of the disallowed characters (and then report it as invalid), not at least one of the allowed character.



          You can negate a character set in a bracket expression with ! (^ also works with bash and a few other shells).



          In any case, you were right to explicitly list characters individually, using ranges like a-z, A-Z, 0-9 would only work (at matching only the 26+26+10 characters you listed) in the C locale. In other locales they could match thousands of other characters or even collating elements made of more than one character (the ones that sort between A and Z like É for instance for A-Z).



          case $URL in
          ("" | *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_/&?:.=-]*)
          echo >&2 "That URL is NOT allowed.";;
          (*)
          echo "That URL is allowed.";;
          esac





          share|improve this answer


























          • Works nicely. Now, regarding the $URL in case $URL in, shouldn't it be wrapped in quotes,       i.e. case "${URL}" in?

            – leetbacoon
            Feb 10 at 22:45













          • @leetbacoon, while those quotes wouldn't harm, they are nor necessary, as it's not a list context (so split+glob won't apply) and it's not a context where a pattern is expected (it would be a different matter in case x in ("$URL")...

            – Stéphane Chazelas
            Feb 17 at 15:02



















          2














          Your attempt



          Your attempt might not work as expected because it considers all URLs as allowed that contain at least one of the allowed characters. Formally, you compare the URL with



          <anything><allowed_character><anything>


          If this does not match, you reject the URL.



          This might help



          If you replace your if ... else ... fi by



          if [[ "${URL}" =~ [^A-Za-z0-9&./=_:?-] ]]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi


          it might do what you want.



          Here, the binary operator =~ is used to find a match of the regular expression [^A-Za-z0-9&./=_-:?] within "${URL}". This operator does not require that the whole string "${URL}" matches the regular expression, any matching substring will do. Such a match is found for any character that is not allowed in the URL. The "not" comes from the leading caret (^) in the definition of the character set. Please note that there is no negating ! in the conditional expression any more.



          If "${URL}" contains a forbidden character, the regular expression matches and the compound command [[...]] evaluates to true (zero exit status).






          share|improve this answer


























          • Just tried this with https://www.youtube.com/watch?v=_! as a sample URL, but it says it's allowed...

            – leetbacoon
            Feb 5 at 1:37











          • @leetbacoon: Sorry, you are absolutely right. I made a mistake in the regular expression: Defining the character set, I did not place the single - at the end, so it was defining the character range _-:. The collate setting in my locale covered that problem. But when the C locale is used, the [[...]] returned exit code 2 for error, which in this case "allows" the URL. Now this is fixed.

            – Jürgen
            Feb 5 at 5:18



















          1














          Your current logic is wrong, it returns true only when every character in the input URL exists outside the set of permitted characters.



          Try something along the lines of



          if [[ "${URL}"  = *[!A-Za-z0-9&./=_:?-]* ]]
          then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed"
          fi


          This check, due to the negation (!) inside the character range, is intended to return true when the input URL contains one or more characters outside of the permitted set






          share|improve this answer
























          • Tested and also working A-OK! :)

            – leetbacoon
            Feb 10 at 22:54



















          1














          Compact solution



          If you prefer a compact solution, you can use this one:



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No || echo Yes


          Explanation



          This solution uses a parameter expansion of the form ${<variable>//<pattern>} which is a special case of the more general form



          ${<variable>//<pattern>/<replace>}


          This is expanded by the shell to the value of <variable>, where all matches of <pattern> are replaced by <replace>. In our case, <replace> is empty, what also allows to omit the slash after <pattern>.



          As a result, "${URL//[A-Za-z0-9&./=_:?-]}" is expanded to the URL with all allowed characters removed. If there are no residues, i.e. the URL is allowed, [ ... ] is actually [ ], which yields false (exit status 0). If there are characters left, they are forbidden, and [ ... ] has the form [ <nes> ], where <nes> is a non-empty string, which yields true (exit status 1).



          The overall command is a list of three commands separated by the control operators && (and) and || (or), which are left-associative. Therefore, the sub-list



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No


          is evaluated first. There, the second operand of && is evaluated if and only if the first one evaluates to true (zero exit status). This is the case if the URL contains forbidden characters. So, the echo gives the right answer in this case, "No", and the exit status of that sub-list comes from this echo command: 0 (true).



          If, in contrast, the URL is allowed, the exit status of that sub-list comes from [ ... ]: 1 (false).



          Now for the rest of the list:



          <sub-list> || echo Yes


          The || operator executes the last command if and only if its first operand is false (exit status different from zero). So we get the "Yes" only if <sub-list> is false, i.e. for an allowed URL, as it should be.



          If structure



          Of course you can use the above [ ... ] command also in an if structure. In most cases this will yield a better readable code:



          if [ "${URL//[A-Za-z0-9&./=_:?-]}" ]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi





          share|improve this answer


























          • No need to escape the slash in the [...] group.

            – Kusalananda
            Feb 5 at 6:48











          • @Kusalananda: Actually, the slash has to be escaped, since it is otherwise mistaken as a part of the parameter expression, which yields ${..//../..} instead of ${..//..}. The former does simply not work.

            – Jürgen
            Feb 5 at 14:07













          • Also tested and working great. I like the compact idea!

            – leetbacoon
            Feb 10 at 22:54












          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
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f498699%2fhow-to-allow-only-certain-characters-in-a-bash-variable%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          4 Answers
          4






          active

          oldest

          votes








          4 Answers
          4






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          6














          You were close.



          You want to check whether the URL contains at least one of the disallowed characters (and then report it as invalid), not at least one of the allowed character.



          You can negate a character set in a bracket expression with ! (^ also works with bash and a few other shells).



          In any case, you were right to explicitly list characters individually, using ranges like a-z, A-Z, 0-9 would only work (at matching only the 26+26+10 characters you listed) in the C locale. In other locales they could match thousands of other characters or even collating elements made of more than one character (the ones that sort between A and Z like É for instance for A-Z).



          case $URL in
          ("" | *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_/&?:.=-]*)
          echo >&2 "That URL is NOT allowed.";;
          (*)
          echo "That URL is allowed.";;
          esac





          share|improve this answer


























          • Works nicely. Now, regarding the $URL in case $URL in, shouldn't it be wrapped in quotes,       i.e. case "${URL}" in?

            – leetbacoon
            Feb 10 at 22:45













          • @leetbacoon, while those quotes wouldn't harm, they are nor necessary, as it's not a list context (so split+glob won't apply) and it's not a context where a pattern is expected (it would be a different matter in case x in ("$URL")...

            – Stéphane Chazelas
            Feb 17 at 15:02
















          6














          You were close.



          You want to check whether the URL contains at least one of the disallowed characters (and then report it as invalid), not at least one of the allowed character.



          You can negate a character set in a bracket expression with ! (^ also works with bash and a few other shells).



          In any case, you were right to explicitly list characters individually, using ranges like a-z, A-Z, 0-9 would only work (at matching only the 26+26+10 characters you listed) in the C locale. In other locales they could match thousands of other characters or even collating elements made of more than one character (the ones that sort between A and Z like É for instance for A-Z).



          case $URL in
          ("" | *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_/&?:.=-]*)
          echo >&2 "That URL is NOT allowed.";;
          (*)
          echo "That URL is allowed.";;
          esac





          share|improve this answer


























          • Works nicely. Now, regarding the $URL in case $URL in, shouldn't it be wrapped in quotes,       i.e. case "${URL}" in?

            – leetbacoon
            Feb 10 at 22:45













          • @leetbacoon, while those quotes wouldn't harm, they are nor necessary, as it's not a list context (so split+glob won't apply) and it's not a context where a pattern is expected (it would be a different matter in case x in ("$URL")...

            – Stéphane Chazelas
            Feb 17 at 15:02














          6












          6








          6







          You were close.



          You want to check whether the URL contains at least one of the disallowed characters (and then report it as invalid), not at least one of the allowed character.



          You can negate a character set in a bracket expression with ! (^ also works with bash and a few other shells).



          In any case, you were right to explicitly list characters individually, using ranges like a-z, A-Z, 0-9 would only work (at matching only the 26+26+10 characters you listed) in the C locale. In other locales they could match thousands of other characters or even collating elements made of more than one character (the ones that sort between A and Z like É for instance for A-Z).



          case $URL in
          ("" | *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_/&?:.=-]*)
          echo >&2 "That URL is NOT allowed.";;
          (*)
          echo "That URL is allowed.";;
          esac





          share|improve this answer















          You were close.



          You want to check whether the URL contains at least one of the disallowed characters (and then report it as invalid), not at least one of the allowed character.



          You can negate a character set in a bracket expression with ! (^ also works with bash and a few other shells).



          In any case, you were right to explicitly list characters individually, using ranges like a-z, A-Z, 0-9 would only work (at matching only the 26+26+10 characters you listed) in the C locale. In other locales they could match thousands of other characters or even collating elements made of more than one character (the ones that sort between A and Z like É for instance for A-Z).



          case $URL in
          ("" | *[!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_/&?:.=-]*)
          echo >&2 "That URL is NOT allowed.";;
          (*)
          echo "That URL is allowed.";;
          esac






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Feb 5 at 8:28

























          answered Feb 5 at 7:47









          Stéphane ChazelasStéphane Chazelas

          315k57597955




          315k57597955













          • Works nicely. Now, regarding the $URL in case $URL in, shouldn't it be wrapped in quotes,       i.e. case "${URL}" in?

            – leetbacoon
            Feb 10 at 22:45













          • @leetbacoon, while those quotes wouldn't harm, they are nor necessary, as it's not a list context (so split+glob won't apply) and it's not a context where a pattern is expected (it would be a different matter in case x in ("$URL")...

            – Stéphane Chazelas
            Feb 17 at 15:02



















          • Works nicely. Now, regarding the $URL in case $URL in, shouldn't it be wrapped in quotes,       i.e. case "${URL}" in?

            – leetbacoon
            Feb 10 at 22:45













          • @leetbacoon, while those quotes wouldn't harm, they are nor necessary, as it's not a list context (so split+glob won't apply) and it's not a context where a pattern is expected (it would be a different matter in case x in ("$URL")...

            – Stéphane Chazelas
            Feb 17 at 15:02

















          Works nicely. Now, regarding the $URL in case $URL in, shouldn't it be wrapped in quotes,       i.e. case "${URL}" in?

          – leetbacoon
          Feb 10 at 22:45







          Works nicely. Now, regarding the $URL in case $URL in, shouldn't it be wrapped in quotes,       i.e. case "${URL}" in?

          – leetbacoon
          Feb 10 at 22:45















          @leetbacoon, while those quotes wouldn't harm, they are nor necessary, as it's not a list context (so split+glob won't apply) and it's not a context where a pattern is expected (it would be a different matter in case x in ("$URL")...

          – Stéphane Chazelas
          Feb 17 at 15:02





          @leetbacoon, while those quotes wouldn't harm, they are nor necessary, as it's not a list context (so split+glob won't apply) and it's not a context where a pattern is expected (it would be a different matter in case x in ("$URL")...

          – Stéphane Chazelas
          Feb 17 at 15:02













          2














          Your attempt



          Your attempt might not work as expected because it considers all URLs as allowed that contain at least one of the allowed characters. Formally, you compare the URL with



          <anything><allowed_character><anything>


          If this does not match, you reject the URL.



          This might help



          If you replace your if ... else ... fi by



          if [[ "${URL}" =~ [^A-Za-z0-9&./=_:?-] ]]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi


          it might do what you want.



          Here, the binary operator =~ is used to find a match of the regular expression [^A-Za-z0-9&./=_-:?] within "${URL}". This operator does not require that the whole string "${URL}" matches the regular expression, any matching substring will do. Such a match is found for any character that is not allowed in the URL. The "not" comes from the leading caret (^) in the definition of the character set. Please note that there is no negating ! in the conditional expression any more.



          If "${URL}" contains a forbidden character, the regular expression matches and the compound command [[...]] evaluates to true (zero exit status).






          share|improve this answer


























          • Just tried this with https://www.youtube.com/watch?v=_! as a sample URL, but it says it's allowed...

            – leetbacoon
            Feb 5 at 1:37











          • @leetbacoon: Sorry, you are absolutely right. I made a mistake in the regular expression: Defining the character set, I did not place the single - at the end, so it was defining the character range _-:. The collate setting in my locale covered that problem. But when the C locale is used, the [[...]] returned exit code 2 for error, which in this case "allows" the URL. Now this is fixed.

            – Jürgen
            Feb 5 at 5:18
















          2














          Your attempt



          Your attempt might not work as expected because it considers all URLs as allowed that contain at least one of the allowed characters. Formally, you compare the URL with



          <anything><allowed_character><anything>


          If this does not match, you reject the URL.



          This might help



          If you replace your if ... else ... fi by



          if [[ "${URL}" =~ [^A-Za-z0-9&./=_:?-] ]]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi


          it might do what you want.



          Here, the binary operator =~ is used to find a match of the regular expression [^A-Za-z0-9&./=_-:?] within "${URL}". This operator does not require that the whole string "${URL}" matches the regular expression, any matching substring will do. Such a match is found for any character that is not allowed in the URL. The "not" comes from the leading caret (^) in the definition of the character set. Please note that there is no negating ! in the conditional expression any more.



          If "${URL}" contains a forbidden character, the regular expression matches and the compound command [[...]] evaluates to true (zero exit status).






          share|improve this answer


























          • Just tried this with https://www.youtube.com/watch?v=_! as a sample URL, but it says it's allowed...

            – leetbacoon
            Feb 5 at 1:37











          • @leetbacoon: Sorry, you are absolutely right. I made a mistake in the regular expression: Defining the character set, I did not place the single - at the end, so it was defining the character range _-:. The collate setting in my locale covered that problem. But when the C locale is used, the [[...]] returned exit code 2 for error, which in this case "allows" the URL. Now this is fixed.

            – Jürgen
            Feb 5 at 5:18














          2












          2








          2







          Your attempt



          Your attempt might not work as expected because it considers all URLs as allowed that contain at least one of the allowed characters. Formally, you compare the URL with



          <anything><allowed_character><anything>


          If this does not match, you reject the URL.



          This might help



          If you replace your if ... else ... fi by



          if [[ "${URL}" =~ [^A-Za-z0-9&./=_:?-] ]]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi


          it might do what you want.



          Here, the binary operator =~ is used to find a match of the regular expression [^A-Za-z0-9&./=_-:?] within "${URL}". This operator does not require that the whole string "${URL}" matches the regular expression, any matching substring will do. Such a match is found for any character that is not allowed in the URL. The "not" comes from the leading caret (^) in the definition of the character set. Please note that there is no negating ! in the conditional expression any more.



          If "${URL}" contains a forbidden character, the regular expression matches and the compound command [[...]] evaluates to true (zero exit status).






          share|improve this answer















          Your attempt



          Your attempt might not work as expected because it considers all URLs as allowed that contain at least one of the allowed characters. Formally, you compare the URL with



          <anything><allowed_character><anything>


          If this does not match, you reject the URL.



          This might help



          If you replace your if ... else ... fi by



          if [[ "${URL}" =~ [^A-Za-z0-9&./=_:?-] ]]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi


          it might do what you want.



          Here, the binary operator =~ is used to find a match of the regular expression [^A-Za-z0-9&./=_-:?] within "${URL}". This operator does not require that the whole string "${URL}" matches the regular expression, any matching substring will do. Such a match is found for any character that is not allowed in the URL. The "not" comes from the leading caret (^) in the definition of the character set. Please note that there is no negating ! in the conditional expression any more.



          If "${URL}" contains a forbidden character, the regular expression matches and the compound command [[...]] evaluates to true (zero exit status).







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Feb 5 at 5:11

























          answered Feb 5 at 0:59









          JürgenJürgen

          192110




          192110













          • Just tried this with https://www.youtube.com/watch?v=_! as a sample URL, but it says it's allowed...

            – leetbacoon
            Feb 5 at 1:37











          • @leetbacoon: Sorry, you are absolutely right. I made a mistake in the regular expression: Defining the character set, I did not place the single - at the end, so it was defining the character range _-:. The collate setting in my locale covered that problem. But when the C locale is used, the [[...]] returned exit code 2 for error, which in this case "allows" the URL. Now this is fixed.

            – Jürgen
            Feb 5 at 5:18



















          • Just tried this with https://www.youtube.com/watch?v=_! as a sample URL, but it says it's allowed...

            – leetbacoon
            Feb 5 at 1:37











          • @leetbacoon: Sorry, you are absolutely right. I made a mistake in the regular expression: Defining the character set, I did not place the single - at the end, so it was defining the character range _-:. The collate setting in my locale covered that problem. But when the C locale is used, the [[...]] returned exit code 2 for error, which in this case "allows" the URL. Now this is fixed.

            – Jürgen
            Feb 5 at 5:18

















          Just tried this with https://www.youtube.com/watch?v=_! as a sample URL, but it says it's allowed...

          – leetbacoon
          Feb 5 at 1:37





          Just tried this with https://www.youtube.com/watch?v=_! as a sample URL, but it says it's allowed...

          – leetbacoon
          Feb 5 at 1:37













          @leetbacoon: Sorry, you are absolutely right. I made a mistake in the regular expression: Defining the character set, I did not place the single - at the end, so it was defining the character range _-:. The collate setting in my locale covered that problem. But when the C locale is used, the [[...]] returned exit code 2 for error, which in this case "allows" the URL. Now this is fixed.

          – Jürgen
          Feb 5 at 5:18





          @leetbacoon: Sorry, you are absolutely right. I made a mistake in the regular expression: Defining the character set, I did not place the single - at the end, so it was defining the character range _-:. The collate setting in my locale covered that problem. But when the C locale is used, the [[...]] returned exit code 2 for error, which in this case "allows" the URL. Now this is fixed.

          – Jürgen
          Feb 5 at 5:18











          1














          Your current logic is wrong, it returns true only when every character in the input URL exists outside the set of permitted characters.



          Try something along the lines of



          if [[ "${URL}"  = *[!A-Za-z0-9&./=_:?-]* ]]
          then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed"
          fi


          This check, due to the negation (!) inside the character range, is intended to return true when the input URL contains one or more characters outside of the permitted set






          share|improve this answer
























          • Tested and also working A-OK! :)

            – leetbacoon
            Feb 10 at 22:54
















          1














          Your current logic is wrong, it returns true only when every character in the input URL exists outside the set of permitted characters.



          Try something along the lines of



          if [[ "${URL}"  = *[!A-Za-z0-9&./=_:?-]* ]]
          then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed"
          fi


          This check, due to the negation (!) inside the character range, is intended to return true when the input URL contains one or more characters outside of the permitted set






          share|improve this answer
























          • Tested and also working A-OK! :)

            – leetbacoon
            Feb 10 at 22:54














          1












          1








          1







          Your current logic is wrong, it returns true only when every character in the input URL exists outside the set of permitted characters.



          Try something along the lines of



          if [[ "${URL}"  = *[!A-Za-z0-9&./=_:?-]* ]]
          then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed"
          fi


          This check, due to the negation (!) inside the character range, is intended to return true when the input URL contains one or more characters outside of the permitted set






          share|improve this answer













          Your current logic is wrong, it returns true only when every character in the input URL exists outside the set of permitted characters.



          Try something along the lines of



          if [[ "${URL}"  = *[!A-Za-z0-9&./=_:?-]* ]]
          then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed"
          fi


          This check, due to the negation (!) inside the character range, is intended to return true when the input URL contains one or more characters outside of the permitted set







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Feb 5 at 1:58









          iruvariruvar

          12.5k63063




          12.5k63063













          • Tested and also working A-OK! :)

            – leetbacoon
            Feb 10 at 22:54



















          • Tested and also working A-OK! :)

            – leetbacoon
            Feb 10 at 22:54

















          Tested and also working A-OK! :)

          – leetbacoon
          Feb 10 at 22:54





          Tested and also working A-OK! :)

          – leetbacoon
          Feb 10 at 22:54











          1














          Compact solution



          If you prefer a compact solution, you can use this one:



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No || echo Yes


          Explanation



          This solution uses a parameter expansion of the form ${<variable>//<pattern>} which is a special case of the more general form



          ${<variable>//<pattern>/<replace>}


          This is expanded by the shell to the value of <variable>, where all matches of <pattern> are replaced by <replace>. In our case, <replace> is empty, what also allows to omit the slash after <pattern>.



          As a result, "${URL//[A-Za-z0-9&./=_:?-]}" is expanded to the URL with all allowed characters removed. If there are no residues, i.e. the URL is allowed, [ ... ] is actually [ ], which yields false (exit status 0). If there are characters left, they are forbidden, and [ ... ] has the form [ <nes> ], where <nes> is a non-empty string, which yields true (exit status 1).



          The overall command is a list of three commands separated by the control operators && (and) and || (or), which are left-associative. Therefore, the sub-list



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No


          is evaluated first. There, the second operand of && is evaluated if and only if the first one evaluates to true (zero exit status). This is the case if the URL contains forbidden characters. So, the echo gives the right answer in this case, "No", and the exit status of that sub-list comes from this echo command: 0 (true).



          If, in contrast, the URL is allowed, the exit status of that sub-list comes from [ ... ]: 1 (false).



          Now for the rest of the list:



          <sub-list> || echo Yes


          The || operator executes the last command if and only if its first operand is false (exit status different from zero). So we get the "Yes" only if <sub-list> is false, i.e. for an allowed URL, as it should be.



          If structure



          Of course you can use the above [ ... ] command also in an if structure. In most cases this will yield a better readable code:



          if [ "${URL//[A-Za-z0-9&./=_:?-]}" ]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi





          share|improve this answer


























          • No need to escape the slash in the [...] group.

            – Kusalananda
            Feb 5 at 6:48











          • @Kusalananda: Actually, the slash has to be escaped, since it is otherwise mistaken as a part of the parameter expression, which yields ${..//../..} instead of ${..//..}. The former does simply not work.

            – Jürgen
            Feb 5 at 14:07













          • Also tested and working great. I like the compact idea!

            – leetbacoon
            Feb 10 at 22:54
















          1














          Compact solution



          If you prefer a compact solution, you can use this one:



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No || echo Yes


          Explanation



          This solution uses a parameter expansion of the form ${<variable>//<pattern>} which is a special case of the more general form



          ${<variable>//<pattern>/<replace>}


          This is expanded by the shell to the value of <variable>, where all matches of <pattern> are replaced by <replace>. In our case, <replace> is empty, what also allows to omit the slash after <pattern>.



          As a result, "${URL//[A-Za-z0-9&./=_:?-]}" is expanded to the URL with all allowed characters removed. If there are no residues, i.e. the URL is allowed, [ ... ] is actually [ ], which yields false (exit status 0). If there are characters left, they are forbidden, and [ ... ] has the form [ <nes> ], where <nes> is a non-empty string, which yields true (exit status 1).



          The overall command is a list of three commands separated by the control operators && (and) and || (or), which are left-associative. Therefore, the sub-list



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No


          is evaluated first. There, the second operand of && is evaluated if and only if the first one evaluates to true (zero exit status). This is the case if the URL contains forbidden characters. So, the echo gives the right answer in this case, "No", and the exit status of that sub-list comes from this echo command: 0 (true).



          If, in contrast, the URL is allowed, the exit status of that sub-list comes from [ ... ]: 1 (false).



          Now for the rest of the list:



          <sub-list> || echo Yes


          The || operator executes the last command if and only if its first operand is false (exit status different from zero). So we get the "Yes" only if <sub-list> is false, i.e. for an allowed URL, as it should be.



          If structure



          Of course you can use the above [ ... ] command also in an if structure. In most cases this will yield a better readable code:



          if [ "${URL//[A-Za-z0-9&./=_:?-]}" ]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi





          share|improve this answer


























          • No need to escape the slash in the [...] group.

            – Kusalananda
            Feb 5 at 6:48











          • @Kusalananda: Actually, the slash has to be escaped, since it is otherwise mistaken as a part of the parameter expression, which yields ${..//../..} instead of ${..//..}. The former does simply not work.

            – Jürgen
            Feb 5 at 14:07













          • Also tested and working great. I like the compact idea!

            – leetbacoon
            Feb 10 at 22:54














          1












          1








          1







          Compact solution



          If you prefer a compact solution, you can use this one:



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No || echo Yes


          Explanation



          This solution uses a parameter expansion of the form ${<variable>//<pattern>} which is a special case of the more general form



          ${<variable>//<pattern>/<replace>}


          This is expanded by the shell to the value of <variable>, where all matches of <pattern> are replaced by <replace>. In our case, <replace> is empty, what also allows to omit the slash after <pattern>.



          As a result, "${URL//[A-Za-z0-9&./=_:?-]}" is expanded to the URL with all allowed characters removed. If there are no residues, i.e. the URL is allowed, [ ... ] is actually [ ], which yields false (exit status 0). If there are characters left, they are forbidden, and [ ... ] has the form [ <nes> ], where <nes> is a non-empty string, which yields true (exit status 1).



          The overall command is a list of three commands separated by the control operators && (and) and || (or), which are left-associative. Therefore, the sub-list



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No


          is evaluated first. There, the second operand of && is evaluated if and only if the first one evaluates to true (zero exit status). This is the case if the URL contains forbidden characters. So, the echo gives the right answer in this case, "No", and the exit status of that sub-list comes from this echo command: 0 (true).



          If, in contrast, the URL is allowed, the exit status of that sub-list comes from [ ... ]: 1 (false).



          Now for the rest of the list:



          <sub-list> || echo Yes


          The || operator executes the last command if and only if its first operand is false (exit status different from zero). So we get the "Yes" only if <sub-list> is false, i.e. for an allowed URL, as it should be.



          If structure



          Of course you can use the above [ ... ] command also in an if structure. In most cases this will yield a better readable code:



          if [ "${URL//[A-Za-z0-9&./=_:?-]}" ]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi





          share|improve this answer















          Compact solution



          If you prefer a compact solution, you can use this one:



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No || echo Yes


          Explanation



          This solution uses a parameter expansion of the form ${<variable>//<pattern>} which is a special case of the more general form



          ${<variable>//<pattern>/<replace>}


          This is expanded by the shell to the value of <variable>, where all matches of <pattern> are replaced by <replace>. In our case, <replace> is empty, what also allows to omit the slash after <pattern>.



          As a result, "${URL//[A-Za-z0-9&./=_:?-]}" is expanded to the URL with all allowed characters removed. If there are no residues, i.e. the URL is allowed, [ ... ] is actually [ ], which yields false (exit status 0). If there are characters left, they are forbidden, and [ ... ] has the form [ <nes> ], where <nes> is a non-empty string, which yields true (exit status 1).



          The overall command is a list of three commands separated by the control operators && (and) and || (or), which are left-associative. Therefore, the sub-list



          [ "${URL//[A-Za-z0-9&./=_:?-]}" ] && echo No


          is evaluated first. There, the second operand of && is evaluated if and only if the first one evaluates to true (zero exit status). This is the case if the URL contains forbidden characters. So, the echo gives the right answer in this case, "No", and the exit status of that sub-list comes from this echo command: 0 (true).



          If, in contrast, the URL is allowed, the exit status of that sub-list comes from [ ... ]: 1 (false).



          Now for the rest of the list:



          <sub-list> || echo Yes


          The || operator executes the last command if and only if its first operand is false (exit status different from zero). So we get the "Yes" only if <sub-list> is false, i.e. for an allowed URL, as it should be.



          If structure



          Of course you can use the above [ ... ] command also in an if structure. In most cases this will yield a better readable code:



          if [ "${URL//[A-Za-z0-9&./=_:?-]}" ]; then
          echo "That URL is NOT allowed."
          else
          echo "That URL is allowed."
          fi






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Feb 5 at 6:34

























          answered Feb 5 at 6:21









          JürgenJürgen

          192110




          192110













          • No need to escape the slash in the [...] group.

            – Kusalananda
            Feb 5 at 6:48











          • @Kusalananda: Actually, the slash has to be escaped, since it is otherwise mistaken as a part of the parameter expression, which yields ${..//../..} instead of ${..//..}. The former does simply not work.

            – Jürgen
            Feb 5 at 14:07













          • Also tested and working great. I like the compact idea!

            – leetbacoon
            Feb 10 at 22:54



















          • No need to escape the slash in the [...] group.

            – Kusalananda
            Feb 5 at 6:48











          • @Kusalananda: Actually, the slash has to be escaped, since it is otherwise mistaken as a part of the parameter expression, which yields ${..//../..} instead of ${..//..}. The former does simply not work.

            – Jürgen
            Feb 5 at 14:07













          • Also tested and working great. I like the compact idea!

            – leetbacoon
            Feb 10 at 22:54

















          No need to escape the slash in the [...] group.

          – Kusalananda
          Feb 5 at 6:48





          No need to escape the slash in the [...] group.

          – Kusalananda
          Feb 5 at 6:48













          @Kusalananda: Actually, the slash has to be escaped, since it is otherwise mistaken as a part of the parameter expression, which yields ${..//../..} instead of ${..//..}. The former does simply not work.

          – Jürgen
          Feb 5 at 14:07







          @Kusalananda: Actually, the slash has to be escaped, since it is otherwise mistaken as a part of the parameter expression, which yields ${..//../..} instead of ${..//..}. The former does simply not work.

          – Jürgen
          Feb 5 at 14:07















          Also tested and working great. I like the compact idea!

          – leetbacoon
          Feb 10 at 22:54





          Also tested and working great. I like the compact idea!

          – leetbacoon
          Feb 10 at 22:54


















          draft saved

          draft discarded




















































          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%2f498699%2fhow-to-allow-only-certain-characters-in-a-bash-variable%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

          Plaza Victoria

          Brian Clough

          Cáceres