Check if a shell variable has more than one line using built-ins?











up vote
3
down vote

favorite
2












I can do this by calling the external utility sed (for a known non-empty $myvar) like so:



if [ "$(printf %s "$myvar" | sed -n '$=')" -eq 1 ]; then
echo "Your variable has only one line, proceeding"
else
echo "Error condition, variable must have only one line"
fi


Is there a way to do this using only bash builtins?



Even better, is there a way to do this in a POSIX-specified manner, without calling external utilities?





(This question is one of curiosity and finding better ways to do things; the above code does function. I'm wondering if there is a cleaner/faster way.)










share|improve this question




















  • 1




    With that function, the result of myvar="ab" is exactly the same as the result of myvar=$'abn'. Should a trailing newline be ignored?. In my opinion, it shouldn't.
    – user79743
    Apr 19 '16 at 23:07










  • @BinaryZebra, you are absolutely correct for the general case. In my specific case, I was setting the variable in the first place using command substitution, so was guaranteed to have no trailing newlines.
    – Wildcard
    Apr 19 '16 at 23:10






  • 1




    So, if the variable has no trailing "new line" and contains no "new line" it should be counted as "one line". If a trailing "new line" is added, it should be counted as "one more", correct?. There is only one case left that the function with sed fails to process and in my opinion should be counted as "one line" (there are no "new lines" included in the variable). ... ... ... what if myvar='' or unset myvar?
    – user79743
    Apr 19 '16 at 23:38










  • @BinaryZebra, this is what I get for failing to assiduously reduce my code to a simplest case standalone example. :) The conditional line itself is taken from my actual production script; the echo lines are obviously filler. Earlier in the script (just after the command substitution) I checked that the variable started with the expected pattern—so I already know the variable is not empty or unset. This is my question post, not an answer, so I don't feel it's necessary to edit it at this point, but feel free to propose one if you see a simple way to make it clearer.
    – Wildcard
    Apr 19 '16 at 23:45








  • 1




    Yes, You need a "simplest case standalone example". :-) ... No edit needed, it is already becoming "an old question", but I took the liberty of proposing one :-) ... feel free to simply "reverse the edit" if you don't like it for any reason. I hope this is the end of the history for this question. Bye.
    – user79743
    Apr 20 '16 at 2:19















up vote
3
down vote

favorite
2












I can do this by calling the external utility sed (for a known non-empty $myvar) like so:



if [ "$(printf %s "$myvar" | sed -n '$=')" -eq 1 ]; then
echo "Your variable has only one line, proceeding"
else
echo "Error condition, variable must have only one line"
fi


Is there a way to do this using only bash builtins?



Even better, is there a way to do this in a POSIX-specified manner, without calling external utilities?





(This question is one of curiosity and finding better ways to do things; the above code does function. I'm wondering if there is a cleaner/faster way.)










share|improve this question




















  • 1




    With that function, the result of myvar="ab" is exactly the same as the result of myvar=$'abn'. Should a trailing newline be ignored?. In my opinion, it shouldn't.
    – user79743
    Apr 19 '16 at 23:07










  • @BinaryZebra, you are absolutely correct for the general case. In my specific case, I was setting the variable in the first place using command substitution, so was guaranteed to have no trailing newlines.
    – Wildcard
    Apr 19 '16 at 23:10






  • 1




    So, if the variable has no trailing "new line" and contains no "new line" it should be counted as "one line". If a trailing "new line" is added, it should be counted as "one more", correct?. There is only one case left that the function with sed fails to process and in my opinion should be counted as "one line" (there are no "new lines" included in the variable). ... ... ... what if myvar='' or unset myvar?
    – user79743
    Apr 19 '16 at 23:38










  • @BinaryZebra, this is what I get for failing to assiduously reduce my code to a simplest case standalone example. :) The conditional line itself is taken from my actual production script; the echo lines are obviously filler. Earlier in the script (just after the command substitution) I checked that the variable started with the expected pattern—so I already know the variable is not empty or unset. This is my question post, not an answer, so I don't feel it's necessary to edit it at this point, but feel free to propose one if you see a simple way to make it clearer.
    – Wildcard
    Apr 19 '16 at 23:45








  • 1




    Yes, You need a "simplest case standalone example". :-) ... No edit needed, it is already becoming "an old question", but I took the liberty of proposing one :-) ... feel free to simply "reverse the edit" if you don't like it for any reason. I hope this is the end of the history for this question. Bye.
    – user79743
    Apr 20 '16 at 2:19













up vote
3
down vote

favorite
2









up vote
3
down vote

favorite
2






2





I can do this by calling the external utility sed (for a known non-empty $myvar) like so:



if [ "$(printf %s "$myvar" | sed -n '$=')" -eq 1 ]; then
echo "Your variable has only one line, proceeding"
else
echo "Error condition, variable must have only one line"
fi


Is there a way to do this using only bash builtins?



Even better, is there a way to do this in a POSIX-specified manner, without calling external utilities?





(This question is one of curiosity and finding better ways to do things; the above code does function. I'm wondering if there is a cleaner/faster way.)










share|improve this question















I can do this by calling the external utility sed (for a known non-empty $myvar) like so:



if [ "$(printf %s "$myvar" | sed -n '$=')" -eq 1 ]; then
echo "Your variable has only one line, proceeding"
else
echo "Error condition, variable must have only one line"
fi


Is there a way to do this using only bash builtins?



Even better, is there a way to do this in a POSIX-specified manner, without calling external utilities?





(This question is one of curiosity and finding better ways to do things; the above code does function. I'm wondering if there is a cleaner/faster way.)







bash shell-script string posix






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Apr 20 '16 at 2:14







user79743

















asked Apr 16 '16 at 3:38









Wildcard

22.5k959164




22.5k959164








  • 1




    With that function, the result of myvar="ab" is exactly the same as the result of myvar=$'abn'. Should a trailing newline be ignored?. In my opinion, it shouldn't.
    – user79743
    Apr 19 '16 at 23:07










  • @BinaryZebra, you are absolutely correct for the general case. In my specific case, I was setting the variable in the first place using command substitution, so was guaranteed to have no trailing newlines.
    – Wildcard
    Apr 19 '16 at 23:10






  • 1




    So, if the variable has no trailing "new line" and contains no "new line" it should be counted as "one line". If a trailing "new line" is added, it should be counted as "one more", correct?. There is only one case left that the function with sed fails to process and in my opinion should be counted as "one line" (there are no "new lines" included in the variable). ... ... ... what if myvar='' or unset myvar?
    – user79743
    Apr 19 '16 at 23:38










  • @BinaryZebra, this is what I get for failing to assiduously reduce my code to a simplest case standalone example. :) The conditional line itself is taken from my actual production script; the echo lines are obviously filler. Earlier in the script (just after the command substitution) I checked that the variable started with the expected pattern—so I already know the variable is not empty or unset. This is my question post, not an answer, so I don't feel it's necessary to edit it at this point, but feel free to propose one if you see a simple way to make it clearer.
    – Wildcard
    Apr 19 '16 at 23:45








  • 1




    Yes, You need a "simplest case standalone example". :-) ... No edit needed, it is already becoming "an old question", but I took the liberty of proposing one :-) ... feel free to simply "reverse the edit" if you don't like it for any reason. I hope this is the end of the history for this question. Bye.
    – user79743
    Apr 20 '16 at 2:19














  • 1




    With that function, the result of myvar="ab" is exactly the same as the result of myvar=$'abn'. Should a trailing newline be ignored?. In my opinion, it shouldn't.
    – user79743
    Apr 19 '16 at 23:07










  • @BinaryZebra, you are absolutely correct for the general case. In my specific case, I was setting the variable in the first place using command substitution, so was guaranteed to have no trailing newlines.
    – Wildcard
    Apr 19 '16 at 23:10






  • 1




    So, if the variable has no trailing "new line" and contains no "new line" it should be counted as "one line". If a trailing "new line" is added, it should be counted as "one more", correct?. There is only one case left that the function with sed fails to process and in my opinion should be counted as "one line" (there are no "new lines" included in the variable). ... ... ... what if myvar='' or unset myvar?
    – user79743
    Apr 19 '16 at 23:38










  • @BinaryZebra, this is what I get for failing to assiduously reduce my code to a simplest case standalone example. :) The conditional line itself is taken from my actual production script; the echo lines are obviously filler. Earlier in the script (just after the command substitution) I checked that the variable started with the expected pattern—so I already know the variable is not empty or unset. This is my question post, not an answer, so I don't feel it's necessary to edit it at this point, but feel free to propose one if you see a simple way to make it clearer.
    – Wildcard
    Apr 19 '16 at 23:45








  • 1




    Yes, You need a "simplest case standalone example". :-) ... No edit needed, it is already becoming "an old question", but I took the liberty of proposing one :-) ... feel free to simply "reverse the edit" if you don't like it for any reason. I hope this is the end of the history for this question. Bye.
    – user79743
    Apr 20 '16 at 2:19








1




1




With that function, the result of myvar="ab" is exactly the same as the result of myvar=$'abn'. Should a trailing newline be ignored?. In my opinion, it shouldn't.
– user79743
Apr 19 '16 at 23:07




With that function, the result of myvar="ab" is exactly the same as the result of myvar=$'abn'. Should a trailing newline be ignored?. In my opinion, it shouldn't.
– user79743
Apr 19 '16 at 23:07












@BinaryZebra, you are absolutely correct for the general case. In my specific case, I was setting the variable in the first place using command substitution, so was guaranteed to have no trailing newlines.
– Wildcard
Apr 19 '16 at 23:10




@BinaryZebra, you are absolutely correct for the general case. In my specific case, I was setting the variable in the first place using command substitution, so was guaranteed to have no trailing newlines.
– Wildcard
Apr 19 '16 at 23:10




1




1




So, if the variable has no trailing "new line" and contains no "new line" it should be counted as "one line". If a trailing "new line" is added, it should be counted as "one more", correct?. There is only one case left that the function with sed fails to process and in my opinion should be counted as "one line" (there are no "new lines" included in the variable). ... ... ... what if myvar='' or unset myvar?
– user79743
Apr 19 '16 at 23:38




So, if the variable has no trailing "new line" and contains no "new line" it should be counted as "one line". If a trailing "new line" is added, it should be counted as "one more", correct?. There is only one case left that the function with sed fails to process and in my opinion should be counted as "one line" (there are no "new lines" included in the variable). ... ... ... what if myvar='' or unset myvar?
– user79743
Apr 19 '16 at 23:38












@BinaryZebra, this is what I get for failing to assiduously reduce my code to a simplest case standalone example. :) The conditional line itself is taken from my actual production script; the echo lines are obviously filler. Earlier in the script (just after the command substitution) I checked that the variable started with the expected pattern—so I already know the variable is not empty or unset. This is my question post, not an answer, so I don't feel it's necessary to edit it at this point, but feel free to propose one if you see a simple way to make it clearer.
– Wildcard
Apr 19 '16 at 23:45






@BinaryZebra, this is what I get for failing to assiduously reduce my code to a simplest case standalone example. :) The conditional line itself is taken from my actual production script; the echo lines are obviously filler. Earlier in the script (just after the command substitution) I checked that the variable started with the expected pattern—so I already know the variable is not empty or unset. This is my question post, not an answer, so I don't feel it's necessary to edit it at this point, but feel free to propose one if you see a simple way to make it clearer.
– Wildcard
Apr 19 '16 at 23:45






1




1




Yes, You need a "simplest case standalone example". :-) ... No edit needed, it is already becoming "an old question", but I took the liberty of proposing one :-) ... feel free to simply "reverse the edit" if you don't like it for any reason. I hope this is the end of the history for this question. Bye.
– user79743
Apr 20 '16 at 2:19




Yes, You need a "simplest case standalone example". :-) ... No edit needed, it is already becoming "an old question", but I took the liberty of proposing one :-) ... feel free to simply "reverse the edit" if you don't like it for any reason. I hope this is the end of the history for this question. Bye.
– user79743
Apr 20 '16 at 2:19










5 Answers
5






active

oldest

votes

















up vote
10
down vote



accepted










The POSIX way:



NL='
'
case $myvar in
*"$NL"*) echo more than one line ;;
*) echo one line ;;
esac


This also works in pre-POSIX Bourne-like shells, too.






share|improve this answer






























    up vote
    5
    down vote













    The following snippets works in bash (with and without the -posix option):



    #!/bin/bash
    #!/bin/bash -posix
    version_1 () { [[ "$myvar" = *$'n'* ]]; }
    version_2 () {
    local newlines="${myvar//[^$'n']/}"
    [[ "${#newlines}" -eq 1 ]]
    }
    for test in version_1 version_2; do
    if $test; then echo many lines; else echo one line; fi
    done





    share|improve this answer






























      up vote
      4
      down vote













      There are several options (bash first, POSIX is below).

      The code inside each function could be easily used outside.



      #!/bin/bash

      nl=$'n'

      aregex (){ [[ $a =~ $nl ]]; }
      apattern (){ [[ $a == *$nl* ]]; }
      acut (){ [[ $a != "${a%%"$nl"*}" ]]; }
      areplace (){ [[ $a != "${a//"$nl"/}" ]]; }
      acase (){ case $a in (*$nl*) true;; (*) false;; esac; }
      aifs ()( IFS="$nl"
      set -f; set -- x${a}x;
      (( $# > 1 ));
      )
      aread (){ IFS="$nl" read -rd '' -a b <<<"x${a}x";
      (( "${#b[@]}" > 1 )); }


      Each function is an option. Each function will exit with a return value of 0 if there is only one line and a return value of 1 if the variable $a has more than one new-line (more than one $'n').



      After a function is executed, this will print the line required:



      out=''; "$function" && out="more than "
      printf "%9s = %sone linen" "$1" "$out"




      Executing all options:



      a='ab'"$nl"'cd' ; alltests
      a='ab cd' ; alltests


      Gives this output:



         aregex   = more than one line
      apattern = more than one line
      acut = more than one line
      areplace = more than one line
      acase = more than one line
      aifs = more than one line
      aread = more than one line

      aregex = one line
      apattern = one line
      acut = one line
      areplace = one line
      acase = one line
      aifs = one line
      aread = one line


      POSIX



      The following options fail in POSIX for several reasons:




      • aregex : There is no regex =~ operators in POSIX.

      • apattern : There is no == operator in POSIX.

      • areplace : Parameter expansion does not have the ${ / / } option.


      Four could safely be translated to POSIX:




      • posixcut : Probably the best solution.

      • posixcase : A common solution for POSIX shells.

      • posixifs : Executed inside a sub-shell to be able to set set -f.

      • posixread : read does not have -d or -a but it could be adapted.




      #!/bin/dash

      nl='
      '

      posixcut (){ [ "${a}" != "${a%%"$nl"*}" ] ; }
      posixcase(){ case $a in (*$nl*) true;; (*) false;; esac; }
      posixifs ()( IFS="$nl";
      set -f; set -- x${a}x;
      [ "$#" -gt 1 ];
      )
      posixread(){ local b=0;
      while IFS=$nl read -r _; do
      b=$((b+1));
      [ $b -gt 1 ] && break;
      done <<-_EOT_
      x${a}x
      _EOT_
      [ $b -gt 1 ];
      }


      Note: Yes, local is not strictly POSIX, but is pretty well supported.

      The local for b, could be safely removed (check for global $b usage).



      Bourne (1977 shell).



      If you need code for the original 1977 Bourne shell, use this:



      posixcase() { case $a in *$nl*) true;; *) false;; esac; }
      posixifs () ( IFS="$nl"
      set -f; set -- x${a}x;
      [ "$#" -gt 1 ];
      )
      bourneread()( b=0 ### A helper function.
      while :; do
      if IFS=$nl read c && [ $b -le 1 ]; then
      b=`expr $b + 1`
      else
      echo "$b"
      break
      fi
      done <<-_EOT_
      x${a}x
      _EOT_
      )
      posixread (){ [ `bourneread` -gt 1 ]; }


      The expansion ${a%% } used in posixcut will not work in Bourne.
      The posixifs needs to be divided in two parts to work in Bourne.

      The read option needs mayor changes, but works correctly.

      Its function is posixread, the bourneread is a required helper function.



      All code for Bourne was tested to be working correctly with heirloom shell.






      share|improve this answer























      • The 1977 Bourne shell had no functions. I'd expect those kind of redirections wouldn't work great there either. Redirection was quite buggy back then there. It's a bit pointless trying to be portable to such an old shell anyway.
        – Stéphane Chazelas
        Apr 19 '16 at 10:02












      • IIRC, It didn't support set -- either. It may have supported set - $var, but set - alone would still be the same as set (again from vague memory). There, you'd need set x $var; shift.
        – Stéphane Chazelas
        Apr 19 '16 at 10:09












      • Testing on a PDP11 emulator running Unix v7, it looks like set - worked there. The need for set x $var; shift might have been for another shell. Note that yash at least doesn't support set - $var.
        – Stéphane Chazelas
        Apr 19 '16 at 10:19










      • @StéphaneChazelas I fully agre with your words: ` It's a bit pointless trying to be portable to such an old shell anyway.` .... Yes, set -- was not there originally: set -- was not implemented originally, but came with the second release of the Bourne shell.. ... ... Yes set x $var; shift would be the usual workaround. ... ... ... ... Thanks for all your informative comments. Bye.
        – user79743
        Apr 19 '16 at 10:32












      • @StéphaneChazelas Where is Unix v7 (for pdp11) available?
        – user79743
        Apr 19 '16 at 10:38


















      up vote
      1
      down vote













      Here is a way that should work with all Bourne syntax / POSIX shells and uses only builtins :



      if (set -f ; IFS=$'n'; set -- x${myvar}x ; [ $# = 1 ]) ; then
      echo "Your variable has only one line, proceeding"
      else
      echo "Error condition, variable must have exactly one line"
      fi


      If your shell doesn't support IFS=$'n' (like dash 0.5.7), you can use instead :



      IFS="
      "





      share|improve this answer























      • I think this you need to set IFS otherwise the answer is wrong: sh -c 'a="x y"; set -- $a; echo $#' prints 2 for me, sh -c $'a="x y"; IFS="n"; set -- $a; echo $#' on the other hand prints 1.
        – Lucas
        Apr 17 '16 at 9:14












      • @Lucas Thanks for your comment, answer updated.
        – jlliagre
        Apr 17 '16 at 10:11










      • The set -f will apply to future commands. You need set -f; set -- $myvar. Also set -- $myvar` on a myvar=$'nnxnnn' would split into 1 element. And myvar='' or myvar=$'nnn' into 0.
        – Stéphane Chazelas
        Apr 18 '16 at 9:30










      • @StéphaneChazelas Thanks Stéphane, I originally used two set instructions when tolf I was missing -f but overlook the issue introduced by an edit that came later. I agree empty lines are still an issue with this approach.
        – jlliagre
        Apr 18 '16 at 13:31










      • @BinaryZebra no problem, the issue was tricky to detect.
        – jlliagre
        Apr 19 '16 at 6:42


















      up vote
      1
      down vote













      I'd recommend using Bash parameter expansion as follows:



      n="${myvar//[^n]}"; if [ ${#n} -eq 1 ]; then
      echo "Your variable has only one line, proceeding"
      else
      echo "Error condition, variable must have only one line"
      fi


      Test Samples:



      myvar="xxx"
      myvar="xxnxx"
      myvar="xxnxnx"





      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',
        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%2f276834%2fcheck-if-a-shell-variable-has-more-than-one-line-using-built-ins%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        5 Answers
        5






        active

        oldest

        votes








        5 Answers
        5






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        10
        down vote



        accepted










        The POSIX way:



        NL='
        '
        case $myvar in
        *"$NL"*) echo more than one line ;;
        *) echo one line ;;
        esac


        This also works in pre-POSIX Bourne-like shells, too.






        share|improve this answer



























          up vote
          10
          down vote



          accepted










          The POSIX way:



          NL='
          '
          case $myvar in
          *"$NL"*) echo more than one line ;;
          *) echo one line ;;
          esac


          This also works in pre-POSIX Bourne-like shells, too.






          share|improve this answer

























            up vote
            10
            down vote



            accepted







            up vote
            10
            down vote



            accepted






            The POSIX way:



            NL='
            '
            case $myvar in
            *"$NL"*) echo more than one line ;;
            *) echo one line ;;
            esac


            This also works in pre-POSIX Bourne-like shells, too.






            share|improve this answer














            The POSIX way:



            NL='
            '
            case $myvar in
            *"$NL"*) echo more than one line ;;
            *) echo one line ;;
            esac


            This also works in pre-POSIX Bourne-like shells, too.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Apr 18 '16 at 9:22









            Stéphane Chazelas

            296k54559902




            296k54559902










            answered Apr 16 '16 at 3:45









            cuonglm

            101k23197299




            101k23197299
























                up vote
                5
                down vote













                The following snippets works in bash (with and without the -posix option):



                #!/bin/bash
                #!/bin/bash -posix
                version_1 () { [[ "$myvar" = *$'n'* ]]; }
                version_2 () {
                local newlines="${myvar//[^$'n']/}"
                [[ "${#newlines}" -eq 1 ]]
                }
                for test in version_1 version_2; do
                if $test; then echo many lines; else echo one line; fi
                done





                share|improve this answer



























                  up vote
                  5
                  down vote













                  The following snippets works in bash (with and without the -posix option):



                  #!/bin/bash
                  #!/bin/bash -posix
                  version_1 () { [[ "$myvar" = *$'n'* ]]; }
                  version_2 () {
                  local newlines="${myvar//[^$'n']/}"
                  [[ "${#newlines}" -eq 1 ]]
                  }
                  for test in version_1 version_2; do
                  if $test; then echo many lines; else echo one line; fi
                  done





                  share|improve this answer

























                    up vote
                    5
                    down vote










                    up vote
                    5
                    down vote









                    The following snippets works in bash (with and without the -posix option):



                    #!/bin/bash
                    #!/bin/bash -posix
                    version_1 () { [[ "$myvar" = *$'n'* ]]; }
                    version_2 () {
                    local newlines="${myvar//[^$'n']/}"
                    [[ "${#newlines}" -eq 1 ]]
                    }
                    for test in version_1 version_2; do
                    if $test; then echo many lines; else echo one line; fi
                    done





                    share|improve this answer














                    The following snippets works in bash (with and without the -posix option):



                    #!/bin/bash
                    #!/bin/bash -posix
                    version_1 () { [[ "$myvar" = *$'n'* ]]; }
                    version_2 () {
                    local newlines="${myvar//[^$'n']/}"
                    [[ "${#newlines}" -eq 1 ]]
                    }
                    for test in version_1 version_2; do
                    if $test; then echo many lines; else echo one line; fi
                    done






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Apr 16 '16 at 16:15









                    Gilles

                    523k12610441576




                    523k12610441576










                    answered Apr 16 '16 at 10:03









                    Lucas

                    1,988717




                    1,988717






















                        up vote
                        4
                        down vote













                        There are several options (bash first, POSIX is below).

                        The code inside each function could be easily used outside.



                        #!/bin/bash

                        nl=$'n'

                        aregex (){ [[ $a =~ $nl ]]; }
                        apattern (){ [[ $a == *$nl* ]]; }
                        acut (){ [[ $a != "${a%%"$nl"*}" ]]; }
                        areplace (){ [[ $a != "${a//"$nl"/}" ]]; }
                        acase (){ case $a in (*$nl*) true;; (*) false;; esac; }
                        aifs ()( IFS="$nl"
                        set -f; set -- x${a}x;
                        (( $# > 1 ));
                        )
                        aread (){ IFS="$nl" read -rd '' -a b <<<"x${a}x";
                        (( "${#b[@]}" > 1 )); }


                        Each function is an option. Each function will exit with a return value of 0 if there is only one line and a return value of 1 if the variable $a has more than one new-line (more than one $'n').



                        After a function is executed, this will print the line required:



                        out=''; "$function" && out="more than "
                        printf "%9s = %sone linen" "$1" "$out"




                        Executing all options:



                        a='ab'"$nl"'cd' ; alltests
                        a='ab cd' ; alltests


                        Gives this output:



                           aregex   = more than one line
                        apattern = more than one line
                        acut = more than one line
                        areplace = more than one line
                        acase = more than one line
                        aifs = more than one line
                        aread = more than one line

                        aregex = one line
                        apattern = one line
                        acut = one line
                        areplace = one line
                        acase = one line
                        aifs = one line
                        aread = one line


                        POSIX



                        The following options fail in POSIX for several reasons:




                        • aregex : There is no regex =~ operators in POSIX.

                        • apattern : There is no == operator in POSIX.

                        • areplace : Parameter expansion does not have the ${ / / } option.


                        Four could safely be translated to POSIX:




                        • posixcut : Probably the best solution.

                        • posixcase : A common solution for POSIX shells.

                        • posixifs : Executed inside a sub-shell to be able to set set -f.

                        • posixread : read does not have -d or -a but it could be adapted.




                        #!/bin/dash

                        nl='
                        '

                        posixcut (){ [ "${a}" != "${a%%"$nl"*}" ] ; }
                        posixcase(){ case $a in (*$nl*) true;; (*) false;; esac; }
                        posixifs ()( IFS="$nl";
                        set -f; set -- x${a}x;
                        [ "$#" -gt 1 ];
                        )
                        posixread(){ local b=0;
                        while IFS=$nl read -r _; do
                        b=$((b+1));
                        [ $b -gt 1 ] && break;
                        done <<-_EOT_
                        x${a}x
                        _EOT_
                        [ $b -gt 1 ];
                        }


                        Note: Yes, local is not strictly POSIX, but is pretty well supported.

                        The local for b, could be safely removed (check for global $b usage).



                        Bourne (1977 shell).



                        If you need code for the original 1977 Bourne shell, use this:



                        posixcase() { case $a in *$nl*) true;; *) false;; esac; }
                        posixifs () ( IFS="$nl"
                        set -f; set -- x${a}x;
                        [ "$#" -gt 1 ];
                        )
                        bourneread()( b=0 ### A helper function.
                        while :; do
                        if IFS=$nl read c && [ $b -le 1 ]; then
                        b=`expr $b + 1`
                        else
                        echo "$b"
                        break
                        fi
                        done <<-_EOT_
                        x${a}x
                        _EOT_
                        )
                        posixread (){ [ `bourneread` -gt 1 ]; }


                        The expansion ${a%% } used in posixcut will not work in Bourne.
                        The posixifs needs to be divided in two parts to work in Bourne.

                        The read option needs mayor changes, but works correctly.

                        Its function is posixread, the bourneread is a required helper function.



                        All code for Bourne was tested to be working correctly with heirloom shell.






                        share|improve this answer























                        • The 1977 Bourne shell had no functions. I'd expect those kind of redirections wouldn't work great there either. Redirection was quite buggy back then there. It's a bit pointless trying to be portable to such an old shell anyway.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:02












                        • IIRC, It didn't support set -- either. It may have supported set - $var, but set - alone would still be the same as set (again from vague memory). There, you'd need set x $var; shift.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:09












                        • Testing on a PDP11 emulator running Unix v7, it looks like set - worked there. The need for set x $var; shift might have been for another shell. Note that yash at least doesn't support set - $var.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:19










                        • @StéphaneChazelas I fully agre with your words: ` It's a bit pointless trying to be portable to such an old shell anyway.` .... Yes, set -- was not there originally: set -- was not implemented originally, but came with the second release of the Bourne shell.. ... ... Yes set x $var; shift would be the usual workaround. ... ... ... ... Thanks for all your informative comments. Bye.
                          – user79743
                          Apr 19 '16 at 10:32












                        • @StéphaneChazelas Where is Unix v7 (for pdp11) available?
                          – user79743
                          Apr 19 '16 at 10:38















                        up vote
                        4
                        down vote













                        There are several options (bash first, POSIX is below).

                        The code inside each function could be easily used outside.



                        #!/bin/bash

                        nl=$'n'

                        aregex (){ [[ $a =~ $nl ]]; }
                        apattern (){ [[ $a == *$nl* ]]; }
                        acut (){ [[ $a != "${a%%"$nl"*}" ]]; }
                        areplace (){ [[ $a != "${a//"$nl"/}" ]]; }
                        acase (){ case $a in (*$nl*) true;; (*) false;; esac; }
                        aifs ()( IFS="$nl"
                        set -f; set -- x${a}x;
                        (( $# > 1 ));
                        )
                        aread (){ IFS="$nl" read -rd '' -a b <<<"x${a}x";
                        (( "${#b[@]}" > 1 )); }


                        Each function is an option. Each function will exit with a return value of 0 if there is only one line and a return value of 1 if the variable $a has more than one new-line (more than one $'n').



                        After a function is executed, this will print the line required:



                        out=''; "$function" && out="more than "
                        printf "%9s = %sone linen" "$1" "$out"




                        Executing all options:



                        a='ab'"$nl"'cd' ; alltests
                        a='ab cd' ; alltests


                        Gives this output:



                           aregex   = more than one line
                        apattern = more than one line
                        acut = more than one line
                        areplace = more than one line
                        acase = more than one line
                        aifs = more than one line
                        aread = more than one line

                        aregex = one line
                        apattern = one line
                        acut = one line
                        areplace = one line
                        acase = one line
                        aifs = one line
                        aread = one line


                        POSIX



                        The following options fail in POSIX for several reasons:




                        • aregex : There is no regex =~ operators in POSIX.

                        • apattern : There is no == operator in POSIX.

                        • areplace : Parameter expansion does not have the ${ / / } option.


                        Four could safely be translated to POSIX:




                        • posixcut : Probably the best solution.

                        • posixcase : A common solution for POSIX shells.

                        • posixifs : Executed inside a sub-shell to be able to set set -f.

                        • posixread : read does not have -d or -a but it could be adapted.




                        #!/bin/dash

                        nl='
                        '

                        posixcut (){ [ "${a}" != "${a%%"$nl"*}" ] ; }
                        posixcase(){ case $a in (*$nl*) true;; (*) false;; esac; }
                        posixifs ()( IFS="$nl";
                        set -f; set -- x${a}x;
                        [ "$#" -gt 1 ];
                        )
                        posixread(){ local b=0;
                        while IFS=$nl read -r _; do
                        b=$((b+1));
                        [ $b -gt 1 ] && break;
                        done <<-_EOT_
                        x${a}x
                        _EOT_
                        [ $b -gt 1 ];
                        }


                        Note: Yes, local is not strictly POSIX, but is pretty well supported.

                        The local for b, could be safely removed (check for global $b usage).



                        Bourne (1977 shell).



                        If you need code for the original 1977 Bourne shell, use this:



                        posixcase() { case $a in *$nl*) true;; *) false;; esac; }
                        posixifs () ( IFS="$nl"
                        set -f; set -- x${a}x;
                        [ "$#" -gt 1 ];
                        )
                        bourneread()( b=0 ### A helper function.
                        while :; do
                        if IFS=$nl read c && [ $b -le 1 ]; then
                        b=`expr $b + 1`
                        else
                        echo "$b"
                        break
                        fi
                        done <<-_EOT_
                        x${a}x
                        _EOT_
                        )
                        posixread (){ [ `bourneread` -gt 1 ]; }


                        The expansion ${a%% } used in posixcut will not work in Bourne.
                        The posixifs needs to be divided in two parts to work in Bourne.

                        The read option needs mayor changes, but works correctly.

                        Its function is posixread, the bourneread is a required helper function.



                        All code for Bourne was tested to be working correctly with heirloom shell.






                        share|improve this answer























                        • The 1977 Bourne shell had no functions. I'd expect those kind of redirections wouldn't work great there either. Redirection was quite buggy back then there. It's a bit pointless trying to be portable to such an old shell anyway.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:02












                        • IIRC, It didn't support set -- either. It may have supported set - $var, but set - alone would still be the same as set (again from vague memory). There, you'd need set x $var; shift.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:09












                        • Testing on a PDP11 emulator running Unix v7, it looks like set - worked there. The need for set x $var; shift might have been for another shell. Note that yash at least doesn't support set - $var.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:19










                        • @StéphaneChazelas I fully agre with your words: ` It's a bit pointless trying to be portable to such an old shell anyway.` .... Yes, set -- was not there originally: set -- was not implemented originally, but came with the second release of the Bourne shell.. ... ... Yes set x $var; shift would be the usual workaround. ... ... ... ... Thanks for all your informative comments. Bye.
                          – user79743
                          Apr 19 '16 at 10:32












                        • @StéphaneChazelas Where is Unix v7 (for pdp11) available?
                          – user79743
                          Apr 19 '16 at 10:38













                        up vote
                        4
                        down vote










                        up vote
                        4
                        down vote









                        There are several options (bash first, POSIX is below).

                        The code inside each function could be easily used outside.



                        #!/bin/bash

                        nl=$'n'

                        aregex (){ [[ $a =~ $nl ]]; }
                        apattern (){ [[ $a == *$nl* ]]; }
                        acut (){ [[ $a != "${a%%"$nl"*}" ]]; }
                        areplace (){ [[ $a != "${a//"$nl"/}" ]]; }
                        acase (){ case $a in (*$nl*) true;; (*) false;; esac; }
                        aifs ()( IFS="$nl"
                        set -f; set -- x${a}x;
                        (( $# > 1 ));
                        )
                        aread (){ IFS="$nl" read -rd '' -a b <<<"x${a}x";
                        (( "${#b[@]}" > 1 )); }


                        Each function is an option. Each function will exit with a return value of 0 if there is only one line and a return value of 1 if the variable $a has more than one new-line (more than one $'n').



                        After a function is executed, this will print the line required:



                        out=''; "$function" && out="more than "
                        printf "%9s = %sone linen" "$1" "$out"




                        Executing all options:



                        a='ab'"$nl"'cd' ; alltests
                        a='ab cd' ; alltests


                        Gives this output:



                           aregex   = more than one line
                        apattern = more than one line
                        acut = more than one line
                        areplace = more than one line
                        acase = more than one line
                        aifs = more than one line
                        aread = more than one line

                        aregex = one line
                        apattern = one line
                        acut = one line
                        areplace = one line
                        acase = one line
                        aifs = one line
                        aread = one line


                        POSIX



                        The following options fail in POSIX for several reasons:




                        • aregex : There is no regex =~ operators in POSIX.

                        • apattern : There is no == operator in POSIX.

                        • areplace : Parameter expansion does not have the ${ / / } option.


                        Four could safely be translated to POSIX:




                        • posixcut : Probably the best solution.

                        • posixcase : A common solution for POSIX shells.

                        • posixifs : Executed inside a sub-shell to be able to set set -f.

                        • posixread : read does not have -d or -a but it could be adapted.




                        #!/bin/dash

                        nl='
                        '

                        posixcut (){ [ "${a}" != "${a%%"$nl"*}" ] ; }
                        posixcase(){ case $a in (*$nl*) true;; (*) false;; esac; }
                        posixifs ()( IFS="$nl";
                        set -f; set -- x${a}x;
                        [ "$#" -gt 1 ];
                        )
                        posixread(){ local b=0;
                        while IFS=$nl read -r _; do
                        b=$((b+1));
                        [ $b -gt 1 ] && break;
                        done <<-_EOT_
                        x${a}x
                        _EOT_
                        [ $b -gt 1 ];
                        }


                        Note: Yes, local is not strictly POSIX, but is pretty well supported.

                        The local for b, could be safely removed (check for global $b usage).



                        Bourne (1977 shell).



                        If you need code for the original 1977 Bourne shell, use this:



                        posixcase() { case $a in *$nl*) true;; *) false;; esac; }
                        posixifs () ( IFS="$nl"
                        set -f; set -- x${a}x;
                        [ "$#" -gt 1 ];
                        )
                        bourneread()( b=0 ### A helper function.
                        while :; do
                        if IFS=$nl read c && [ $b -le 1 ]; then
                        b=`expr $b + 1`
                        else
                        echo "$b"
                        break
                        fi
                        done <<-_EOT_
                        x${a}x
                        _EOT_
                        )
                        posixread (){ [ `bourneread` -gt 1 ]; }


                        The expansion ${a%% } used in posixcut will not work in Bourne.
                        The posixifs needs to be divided in two parts to work in Bourne.

                        The read option needs mayor changes, but works correctly.

                        Its function is posixread, the bourneread is a required helper function.



                        All code for Bourne was tested to be working correctly with heirloom shell.






                        share|improve this answer














                        There are several options (bash first, POSIX is below).

                        The code inside each function could be easily used outside.



                        #!/bin/bash

                        nl=$'n'

                        aregex (){ [[ $a =~ $nl ]]; }
                        apattern (){ [[ $a == *$nl* ]]; }
                        acut (){ [[ $a != "${a%%"$nl"*}" ]]; }
                        areplace (){ [[ $a != "${a//"$nl"/}" ]]; }
                        acase (){ case $a in (*$nl*) true;; (*) false;; esac; }
                        aifs ()( IFS="$nl"
                        set -f; set -- x${a}x;
                        (( $# > 1 ));
                        )
                        aread (){ IFS="$nl" read -rd '' -a b <<<"x${a}x";
                        (( "${#b[@]}" > 1 )); }


                        Each function is an option. Each function will exit with a return value of 0 if there is only one line and a return value of 1 if the variable $a has more than one new-line (more than one $'n').



                        After a function is executed, this will print the line required:



                        out=''; "$function" && out="more than "
                        printf "%9s = %sone linen" "$1" "$out"




                        Executing all options:



                        a='ab'"$nl"'cd' ; alltests
                        a='ab cd' ; alltests


                        Gives this output:



                           aregex   = more than one line
                        apattern = more than one line
                        acut = more than one line
                        areplace = more than one line
                        acase = more than one line
                        aifs = more than one line
                        aread = more than one line

                        aregex = one line
                        apattern = one line
                        acut = one line
                        areplace = one line
                        acase = one line
                        aifs = one line
                        aread = one line


                        POSIX



                        The following options fail in POSIX for several reasons:




                        • aregex : There is no regex =~ operators in POSIX.

                        • apattern : There is no == operator in POSIX.

                        • areplace : Parameter expansion does not have the ${ / / } option.


                        Four could safely be translated to POSIX:




                        • posixcut : Probably the best solution.

                        • posixcase : A common solution for POSIX shells.

                        • posixifs : Executed inside a sub-shell to be able to set set -f.

                        • posixread : read does not have -d or -a but it could be adapted.




                        #!/bin/dash

                        nl='
                        '

                        posixcut (){ [ "${a}" != "${a%%"$nl"*}" ] ; }
                        posixcase(){ case $a in (*$nl*) true;; (*) false;; esac; }
                        posixifs ()( IFS="$nl";
                        set -f; set -- x${a}x;
                        [ "$#" -gt 1 ];
                        )
                        posixread(){ local b=0;
                        while IFS=$nl read -r _; do
                        b=$((b+1));
                        [ $b -gt 1 ] && break;
                        done <<-_EOT_
                        x${a}x
                        _EOT_
                        [ $b -gt 1 ];
                        }


                        Note: Yes, local is not strictly POSIX, but is pretty well supported.

                        The local for b, could be safely removed (check for global $b usage).



                        Bourne (1977 shell).



                        If you need code for the original 1977 Bourne shell, use this:



                        posixcase() { case $a in *$nl*) true;; *) false;; esac; }
                        posixifs () ( IFS="$nl"
                        set -f; set -- x${a}x;
                        [ "$#" -gt 1 ];
                        )
                        bourneread()( b=0 ### A helper function.
                        while :; do
                        if IFS=$nl read c && [ $b -le 1 ]; then
                        b=`expr $b + 1`
                        else
                        echo "$b"
                        break
                        fi
                        done <<-_EOT_
                        x${a}x
                        _EOT_
                        )
                        posixread (){ [ `bourneread` -gt 1 ]; }


                        The expansion ${a%% } used in posixcut will not work in Bourne.
                        The posixifs needs to be divided in two parts to work in Bourne.

                        The read option needs mayor changes, but works correctly.

                        Its function is posixread, the bourneread is a required helper function.



                        All code for Bourne was tested to be working correctly with heirloom shell.







                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Apr 19 '16 at 1:35

























                        answered Apr 17 '16 at 8:11







                        user79743



















                        • The 1977 Bourne shell had no functions. I'd expect those kind of redirections wouldn't work great there either. Redirection was quite buggy back then there. It's a bit pointless trying to be portable to such an old shell anyway.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:02












                        • IIRC, It didn't support set -- either. It may have supported set - $var, but set - alone would still be the same as set (again from vague memory). There, you'd need set x $var; shift.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:09












                        • Testing on a PDP11 emulator running Unix v7, it looks like set - worked there. The need for set x $var; shift might have been for another shell. Note that yash at least doesn't support set - $var.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:19










                        • @StéphaneChazelas I fully agre with your words: ` It's a bit pointless trying to be portable to such an old shell anyway.` .... Yes, set -- was not there originally: set -- was not implemented originally, but came with the second release of the Bourne shell.. ... ... Yes set x $var; shift would be the usual workaround. ... ... ... ... Thanks for all your informative comments. Bye.
                          – user79743
                          Apr 19 '16 at 10:32












                        • @StéphaneChazelas Where is Unix v7 (for pdp11) available?
                          – user79743
                          Apr 19 '16 at 10:38


















                        • The 1977 Bourne shell had no functions. I'd expect those kind of redirections wouldn't work great there either. Redirection was quite buggy back then there. It's a bit pointless trying to be portable to such an old shell anyway.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:02












                        • IIRC, It didn't support set -- either. It may have supported set - $var, but set - alone would still be the same as set (again from vague memory). There, you'd need set x $var; shift.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:09












                        • Testing on a PDP11 emulator running Unix v7, it looks like set - worked there. The need for set x $var; shift might have been for another shell. Note that yash at least doesn't support set - $var.
                          – Stéphane Chazelas
                          Apr 19 '16 at 10:19










                        • @StéphaneChazelas I fully agre with your words: ` It's a bit pointless trying to be portable to such an old shell anyway.` .... Yes, set -- was not there originally: set -- was not implemented originally, but came with the second release of the Bourne shell.. ... ... Yes set x $var; shift would be the usual workaround. ... ... ... ... Thanks for all your informative comments. Bye.
                          – user79743
                          Apr 19 '16 at 10:32












                        • @StéphaneChazelas Where is Unix v7 (for pdp11) available?
                          – user79743
                          Apr 19 '16 at 10:38
















                        The 1977 Bourne shell had no functions. I'd expect those kind of redirections wouldn't work great there either. Redirection was quite buggy back then there. It's a bit pointless trying to be portable to such an old shell anyway.
                        – Stéphane Chazelas
                        Apr 19 '16 at 10:02






                        The 1977 Bourne shell had no functions. I'd expect those kind of redirections wouldn't work great there either. Redirection was quite buggy back then there. It's a bit pointless trying to be portable to such an old shell anyway.
                        – Stéphane Chazelas
                        Apr 19 '16 at 10:02














                        IIRC, It didn't support set -- either. It may have supported set - $var, but set - alone would still be the same as set (again from vague memory). There, you'd need set x $var; shift.
                        – Stéphane Chazelas
                        Apr 19 '16 at 10:09






                        IIRC, It didn't support set -- either. It may have supported set - $var, but set - alone would still be the same as set (again from vague memory). There, you'd need set x $var; shift.
                        – Stéphane Chazelas
                        Apr 19 '16 at 10:09














                        Testing on a PDP11 emulator running Unix v7, it looks like set - worked there. The need for set x $var; shift might have been for another shell. Note that yash at least doesn't support set - $var.
                        – Stéphane Chazelas
                        Apr 19 '16 at 10:19




                        Testing on a PDP11 emulator running Unix v7, it looks like set - worked there. The need for set x $var; shift might have been for another shell. Note that yash at least doesn't support set - $var.
                        – Stéphane Chazelas
                        Apr 19 '16 at 10:19












                        @StéphaneChazelas I fully agre with your words: ` It's a bit pointless trying to be portable to such an old shell anyway.` .... Yes, set -- was not there originally: set -- was not implemented originally, but came with the second release of the Bourne shell.. ... ... Yes set x $var; shift would be the usual workaround. ... ... ... ... Thanks for all your informative comments. Bye.
                        – user79743
                        Apr 19 '16 at 10:32






                        @StéphaneChazelas I fully agre with your words: ` It's a bit pointless trying to be portable to such an old shell anyway.` .... Yes, set -- was not there originally: set -- was not implemented originally, but came with the second release of the Bourne shell.. ... ... Yes set x $var; shift would be the usual workaround. ... ... ... ... Thanks for all your informative comments. Bye.
                        – user79743
                        Apr 19 '16 at 10:32














                        @StéphaneChazelas Where is Unix v7 (for pdp11) available?
                        – user79743
                        Apr 19 '16 at 10:38




                        @StéphaneChazelas Where is Unix v7 (for pdp11) available?
                        – user79743
                        Apr 19 '16 at 10:38










                        up vote
                        1
                        down vote













                        Here is a way that should work with all Bourne syntax / POSIX shells and uses only builtins :



                        if (set -f ; IFS=$'n'; set -- x${myvar}x ; [ $# = 1 ]) ; then
                        echo "Your variable has only one line, proceeding"
                        else
                        echo "Error condition, variable must have exactly one line"
                        fi


                        If your shell doesn't support IFS=$'n' (like dash 0.5.7), you can use instead :



                        IFS="
                        "





                        share|improve this answer























                        • I think this you need to set IFS otherwise the answer is wrong: sh -c 'a="x y"; set -- $a; echo $#' prints 2 for me, sh -c $'a="x y"; IFS="n"; set -- $a; echo $#' on the other hand prints 1.
                          – Lucas
                          Apr 17 '16 at 9:14












                        • @Lucas Thanks for your comment, answer updated.
                          – jlliagre
                          Apr 17 '16 at 10:11










                        • The set -f will apply to future commands. You need set -f; set -- $myvar. Also set -- $myvar` on a myvar=$'nnxnnn' would split into 1 element. And myvar='' or myvar=$'nnn' into 0.
                          – Stéphane Chazelas
                          Apr 18 '16 at 9:30










                        • @StéphaneChazelas Thanks Stéphane, I originally used two set instructions when tolf I was missing -f but overlook the issue introduced by an edit that came later. I agree empty lines are still an issue with this approach.
                          – jlliagre
                          Apr 18 '16 at 13:31










                        • @BinaryZebra no problem, the issue was tricky to detect.
                          – jlliagre
                          Apr 19 '16 at 6:42















                        up vote
                        1
                        down vote













                        Here is a way that should work with all Bourne syntax / POSIX shells and uses only builtins :



                        if (set -f ; IFS=$'n'; set -- x${myvar}x ; [ $# = 1 ]) ; then
                        echo "Your variable has only one line, proceeding"
                        else
                        echo "Error condition, variable must have exactly one line"
                        fi


                        If your shell doesn't support IFS=$'n' (like dash 0.5.7), you can use instead :



                        IFS="
                        "





                        share|improve this answer























                        • I think this you need to set IFS otherwise the answer is wrong: sh -c 'a="x y"; set -- $a; echo $#' prints 2 for me, sh -c $'a="x y"; IFS="n"; set -- $a; echo $#' on the other hand prints 1.
                          – Lucas
                          Apr 17 '16 at 9:14












                        • @Lucas Thanks for your comment, answer updated.
                          – jlliagre
                          Apr 17 '16 at 10:11










                        • The set -f will apply to future commands. You need set -f; set -- $myvar. Also set -- $myvar` on a myvar=$'nnxnnn' would split into 1 element. And myvar='' or myvar=$'nnn' into 0.
                          – Stéphane Chazelas
                          Apr 18 '16 at 9:30










                        • @StéphaneChazelas Thanks Stéphane, I originally used two set instructions when tolf I was missing -f but overlook the issue introduced by an edit that came later. I agree empty lines are still an issue with this approach.
                          – jlliagre
                          Apr 18 '16 at 13:31










                        • @BinaryZebra no problem, the issue was tricky to detect.
                          – jlliagre
                          Apr 19 '16 at 6:42













                        up vote
                        1
                        down vote










                        up vote
                        1
                        down vote









                        Here is a way that should work with all Bourne syntax / POSIX shells and uses only builtins :



                        if (set -f ; IFS=$'n'; set -- x${myvar}x ; [ $# = 1 ]) ; then
                        echo "Your variable has only one line, proceeding"
                        else
                        echo "Error condition, variable must have exactly one line"
                        fi


                        If your shell doesn't support IFS=$'n' (like dash 0.5.7), you can use instead :



                        IFS="
                        "





                        share|improve this answer














                        Here is a way that should work with all Bourne syntax / POSIX shells and uses only builtins :



                        if (set -f ; IFS=$'n'; set -- x${myvar}x ; [ $# = 1 ]) ; then
                        echo "Your variable has only one line, proceeding"
                        else
                        echo "Error condition, variable must have exactly one line"
                        fi


                        If your shell doesn't support IFS=$'n' (like dash 0.5.7), you can use instead :



                        IFS="
                        "






                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Apr 19 '16 at 10:04







                        user79743

















                        answered Apr 17 '16 at 8:40









                        jlliagre

                        46.1k783132




                        46.1k783132












                        • I think this you need to set IFS otherwise the answer is wrong: sh -c 'a="x y"; set -- $a; echo $#' prints 2 for me, sh -c $'a="x y"; IFS="n"; set -- $a; echo $#' on the other hand prints 1.
                          – Lucas
                          Apr 17 '16 at 9:14












                        • @Lucas Thanks for your comment, answer updated.
                          – jlliagre
                          Apr 17 '16 at 10:11










                        • The set -f will apply to future commands. You need set -f; set -- $myvar. Also set -- $myvar` on a myvar=$'nnxnnn' would split into 1 element. And myvar='' or myvar=$'nnn' into 0.
                          – Stéphane Chazelas
                          Apr 18 '16 at 9:30










                        • @StéphaneChazelas Thanks Stéphane, I originally used two set instructions when tolf I was missing -f but overlook the issue introduced by an edit that came later. I agree empty lines are still an issue with this approach.
                          – jlliagre
                          Apr 18 '16 at 13:31










                        • @BinaryZebra no problem, the issue was tricky to detect.
                          – jlliagre
                          Apr 19 '16 at 6:42


















                        • I think this you need to set IFS otherwise the answer is wrong: sh -c 'a="x y"; set -- $a; echo $#' prints 2 for me, sh -c $'a="x y"; IFS="n"; set -- $a; echo $#' on the other hand prints 1.
                          – Lucas
                          Apr 17 '16 at 9:14












                        • @Lucas Thanks for your comment, answer updated.
                          – jlliagre
                          Apr 17 '16 at 10:11










                        • The set -f will apply to future commands. You need set -f; set -- $myvar. Also set -- $myvar` on a myvar=$'nnxnnn' would split into 1 element. And myvar='' or myvar=$'nnn' into 0.
                          – Stéphane Chazelas
                          Apr 18 '16 at 9:30










                        • @StéphaneChazelas Thanks Stéphane, I originally used two set instructions when tolf I was missing -f but overlook the issue introduced by an edit that came later. I agree empty lines are still an issue with this approach.
                          – jlliagre
                          Apr 18 '16 at 13:31










                        • @BinaryZebra no problem, the issue was tricky to detect.
                          – jlliagre
                          Apr 19 '16 at 6:42
















                        I think this you need to set IFS otherwise the answer is wrong: sh -c 'a="x y"; set -- $a; echo $#' prints 2 for me, sh -c $'a="x y"; IFS="n"; set -- $a; echo $#' on the other hand prints 1.
                        – Lucas
                        Apr 17 '16 at 9:14






                        I think this you need to set IFS otherwise the answer is wrong: sh -c 'a="x y"; set -- $a; echo $#' prints 2 for me, sh -c $'a="x y"; IFS="n"; set -- $a; echo $#' on the other hand prints 1.
                        – Lucas
                        Apr 17 '16 at 9:14














                        @Lucas Thanks for your comment, answer updated.
                        – jlliagre
                        Apr 17 '16 at 10:11




                        @Lucas Thanks for your comment, answer updated.
                        – jlliagre
                        Apr 17 '16 at 10:11












                        The set -f will apply to future commands. You need set -f; set -- $myvar. Also set -- $myvar` on a myvar=$'nnxnnn' would split into 1 element. And myvar='' or myvar=$'nnn' into 0.
                        – Stéphane Chazelas
                        Apr 18 '16 at 9:30




                        The set -f will apply to future commands. You need set -f; set -- $myvar. Also set -- $myvar` on a myvar=$'nnxnnn' would split into 1 element. And myvar='' or myvar=$'nnn' into 0.
                        – Stéphane Chazelas
                        Apr 18 '16 at 9:30












                        @StéphaneChazelas Thanks Stéphane, I originally used two set instructions when tolf I was missing -f but overlook the issue introduced by an edit that came later. I agree empty lines are still an issue with this approach.
                        – jlliagre
                        Apr 18 '16 at 13:31




                        @StéphaneChazelas Thanks Stéphane, I originally used two set instructions when tolf I was missing -f but overlook the issue introduced by an edit that came later. I agree empty lines are still an issue with this approach.
                        – jlliagre
                        Apr 18 '16 at 13:31












                        @BinaryZebra no problem, the issue was tricky to detect.
                        – jlliagre
                        Apr 19 '16 at 6:42




                        @BinaryZebra no problem, the issue was tricky to detect.
                        – jlliagre
                        Apr 19 '16 at 6:42










                        up vote
                        1
                        down vote













                        I'd recommend using Bash parameter expansion as follows:



                        n="${myvar//[^n]}"; if [ ${#n} -eq 1 ]; then
                        echo "Your variable has only one line, proceeding"
                        else
                        echo "Error condition, variable must have only one line"
                        fi


                        Test Samples:



                        myvar="xxx"
                        myvar="xxnxx"
                        myvar="xxnxnx"





                        share|improve this answer

























                          up vote
                          1
                          down vote













                          I'd recommend using Bash parameter expansion as follows:



                          n="${myvar//[^n]}"; if [ ${#n} -eq 1 ]; then
                          echo "Your variable has only one line, proceeding"
                          else
                          echo "Error condition, variable must have only one line"
                          fi


                          Test Samples:



                          myvar="xxx"
                          myvar="xxnxx"
                          myvar="xxnxnx"





                          share|improve this answer























                            up vote
                            1
                            down vote










                            up vote
                            1
                            down vote









                            I'd recommend using Bash parameter expansion as follows:



                            n="${myvar//[^n]}"; if [ ${#n} -eq 1 ]; then
                            echo "Your variable has only one line, proceeding"
                            else
                            echo "Error condition, variable must have only one line"
                            fi


                            Test Samples:



                            myvar="xxx"
                            myvar="xxnxx"
                            myvar="xxnxnx"





                            share|improve this answer












                            I'd recommend using Bash parameter expansion as follows:



                            n="${myvar//[^n]}"; if [ ${#n} -eq 1 ]; then
                            echo "Your variable has only one line, proceeding"
                            else
                            echo "Error condition, variable must have only one line"
                            fi


                            Test Samples:



                            myvar="xxx"
                            myvar="xxnxx"
                            myvar="xxnxnx"






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Nov 29 at 18:11









                            l3x

                            1213




                            1213






























                                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.





                                Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                Please pay close attention to the following guidance:


                                • 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%2f276834%2fcheck-if-a-shell-variable-has-more-than-one-line-using-built-ins%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

                                サソリ

                                広島県道265号伴広島線

                                Accessing regular linux commands in Huawei's Dopra Linux