Read lines into array, one element per line using bash











up vote
0
down vote

favorite












I am trying to get a bash array of all the unstaged modifications of files in a directory (using Git). The following code works to print out all the modified files in a directory:



git -C $dir/.. status --porcelain | grep "^.w" | cut -c 4-


This prints



"Directory Name/File B.txt"
"File A.txt"




I tried using



arr1=($(git status --porcelain | grep "^.w" | cut -c 4-))


but then



for a in "${arr1[@]}"; do echo "$a"; done


(both with and without the quotes around ${arr1[@]} prints



"Directory
Name/File
B.txt"
"File
A.txt"




I also tried



git -C $dir/.. status --porcelain | grep "^.w" | cut -c 4- | readarray arr2


but then



for a in "${arr2[@]}"; do echo "$a"; done


(both with and without the quotes around ${arr2[@]}) prints nothing. Using declare -a arr2 beforehand does absolutely nothing either.





My question is this: How can I read in these values into an array? (This is being used for my argos plugin gitbar, in case it matters, so you can see all my code).










share|improve this question


























    up vote
    0
    down vote

    favorite












    I am trying to get a bash array of all the unstaged modifications of files in a directory (using Git). The following code works to print out all the modified files in a directory:



    git -C $dir/.. status --porcelain | grep "^.w" | cut -c 4-


    This prints



    "Directory Name/File B.txt"
    "File A.txt"




    I tried using



    arr1=($(git status --porcelain | grep "^.w" | cut -c 4-))


    but then



    for a in "${arr1[@]}"; do echo "$a"; done


    (both with and without the quotes around ${arr1[@]} prints



    "Directory
    Name/File
    B.txt"
    "File
    A.txt"




    I also tried



    git -C $dir/.. status --porcelain | grep "^.w" | cut -c 4- | readarray arr2


    but then



    for a in "${arr2[@]}"; do echo "$a"; done


    (both with and without the quotes around ${arr2[@]}) prints nothing. Using declare -a arr2 beforehand does absolutely nothing either.





    My question is this: How can I read in these values into an array? (This is being used for my argos plugin gitbar, in case it matters, so you can see all my code).










    share|improve this question
























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I am trying to get a bash array of all the unstaged modifications of files in a directory (using Git). The following code works to print out all the modified files in a directory:



      git -C $dir/.. status --porcelain | grep "^.w" | cut -c 4-


      This prints



      "Directory Name/File B.txt"
      "File A.txt"




      I tried using



      arr1=($(git status --porcelain | grep "^.w" | cut -c 4-))


      but then



      for a in "${arr1[@]}"; do echo "$a"; done


      (both with and without the quotes around ${arr1[@]} prints



      "Directory
      Name/File
      B.txt"
      "File
      A.txt"




      I also tried



      git -C $dir/.. status --porcelain | grep "^.w" | cut -c 4- | readarray arr2


      but then



      for a in "${arr2[@]}"; do echo "$a"; done


      (both with and without the quotes around ${arr2[@]}) prints nothing. Using declare -a arr2 beforehand does absolutely nothing either.





      My question is this: How can I read in these values into an array? (This is being used for my argos plugin gitbar, in case it matters, so you can see all my code).










      share|improve this question













      I am trying to get a bash array of all the unstaged modifications of files in a directory (using Git). The following code works to print out all the modified files in a directory:



      git -C $dir/.. status --porcelain | grep "^.w" | cut -c 4-


      This prints



      "Directory Name/File B.txt"
      "File A.txt"




      I tried using



      arr1=($(git status --porcelain | grep "^.w" | cut -c 4-))


      but then



      for a in "${arr1[@]}"; do echo "$a"; done


      (both with and without the quotes around ${arr1[@]} prints



      "Directory
      Name/File
      B.txt"
      "File
      A.txt"




      I also tried



      git -C $dir/.. status --porcelain | grep "^.w" | cut -c 4- | readarray arr2


      but then



      for a in "${arr2[@]}"; do echo "$a"; done


      (both with and without the quotes around ${arr2[@]}) prints nothing. Using declare -a arr2 beforehand does absolutely nothing either.





      My question is this: How can I read in these values into an array? (This is being used for my argos plugin gitbar, in case it matters, so you can see all my code).







      bash shell-script git






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 30 at 18:21









      vikarjramun

      1357




      1357






















          3 Answers
          3






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          TL;DR



          In bash:



          readarray -t arr2 < <(git … )
          printf '%sn' "${arr2[@]}"




          There are two distinct problems on your question





          1. Shell splitting.

            When you did:



            arr1=($(git … ))


            the "command expansion" is unquoted, and so: it is subject to shell split and glob.



            The exactly see what that shell splitting do, use printf:



            $ printf '<%s>  '  $(echo word '"one simple sentence"')
            <word> <"one> <simple> <sentence">


            That would be avoided by quoting:



            $ printf '<%s>  '  "$(echo word '"one simple sentence"')"
            <word "one simple sentence">


            But that, also, would avoid the splitting on newlines that you want.




          2. Pipe

            When you executed:



            git … | … | … | readarray arr2


            The array variable arr2 got set but it went away when the pipe (|) was closed.



            You could use the value if you stay inside the last subshell:



            $ printf '%sn' "First value." "Second value." | 
            { readarray -t arr2; printf '%sn' "${arr2[@]}"; }
            First value.
            Second value.


            But the value of arr2 will not survive out of the pipe.




          Solution(s)



          You need to use read to split on newlines but not with a pipe.

          From older to newer:





          1. Loop.

            For old shells without arrays (using positional arguments, the only quasi-array):



            set --
            while IFS='' read -r value; do
            set -- "$@" "$value"
            done <<-EOT
            $(printf '%sn' "First value." "Second value.")
            EOT

            printf '%sn' "$@"


            To set an array (ksh, zsh, bash)



            i=0; arr1=()
            while IFS='' read -r value; do
            arr1+=("$value")
            done <<-EOT
            $(printf '%sn' "First value." "Second value.")
            EOT

            printf '%sn' "${arr1[@]}"



          2. Here-string

            Instead of the here document (<<) we can use a here-string (<<<):



            i=0; arr1=()
            while IFS='' read -r value; do
            arr1+=("$value")
            done <<<"$(printf '%sn' "First value." "Second value.")"

            printf '%sn' "${arr1[@]}"



          3. Process substitution

            In shells that support it (ksh, zsh, bash) you can use <( … ) to replace the here-string:



            i=0; arr1=()
            while IFS='' read -r value; do
            arr1+=("$value")
            done < <(printf '%sn' "First value." "Second value.")

            printf '%sn' "${arr1[@]}"


            With differences: <( ) is able to emit NUL bytes while a here-string might remove (or emit a warning) the NULs. A here-string adds a trailing newline by default. There may be others AFAIK.




          4. readarray

            Use readarray in bash[a] (a.k.a mapfile) to avoid the loop:



            readarray -t arr2 < <(printf '%sn' "First value." "Second value.")
            printf '%sn' "${arr2[@]}"





          [a]In ksh you will need to use read -A, which clears the variable before use, but needs some "magic" to split on newlines and read the whole input at once.



          IFS=$'n' read -d '' -A arr2 < <(printf '%sn' "First value." "Second value.")


          You will need to load a mapfile module in zsh to do something similar.






          share|improve this answer























          • Thank you so much for your clear answer. I have one question: You suggested a here-string (<<<"$(...)"), Jeff Schaller suggested using process substitution (< <(...)). Will there be a difference between the two, perhaps performance or spawning more processes? In the latter, will Bash still write to the temp file, and then read that back in, or will it be smart enough to directly pipe input from the git commands into readarray? If they both end up the same, I feel like < <(...) syntax looks cleaner, but I would rather not use that syntax if it actually creates and writes to a file.
            – vikarjramun
            Nov 30 at 22:45










          • All: <<< like << and <(…) use a temporary file so that commands that lseek their stdin can use them. Use any (in terms of speed or number of processes spawned).
            – Isaac
            Nov 30 at 22:56










          • Does piping also use a temporary file? If not, why doesn't <<< use the same mechanism as piping?
            – vikarjramun
            Nov 30 at 22:58










          • Does piping also use a temporary file? No. Don't know of any condition or shell that does. ……*why doesn't <<< use the same mechanism as piping?* That is a great question for a shell developer, or as a new question. I believe (personal opinion) that it got implemented as a sub-shell the first time around and that concept has worked well enough until now, no need to change? Legacy? You pick.
            – Isaac
            Nov 30 at 23:14










          • Okay, thanks again!
            – vikarjramun
            Nov 30 at 23:17


















          up vote
          2
          down vote













          When you piped to readarray, you started a subshell which correctly populated an arr2 array, but then exited. Use process substitution as the input to readarray:



          readarray -t arr2 < <(git ...)





          share|improve this answer




























            up vote
            1
            down vote













            You are close



            This is a "file names with space character" problem.



            By default, the separator is the space character. It is the IFS environment variable that sets this.



            To change temporarily your environment variable use this:



            ifs_backup=$IFS
            IFS=$(echo -en "nb")


            Then your output for this command:



            for a in "${arr1[@]}"; do echo "$a"; done


            will be:



            "Directory Name/File B.txt"
            "File A.txt"


            To restore IFS :



            IFS=$ifs_backup





            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%2f485221%2fread-lines-into-array-one-element-per-line-using-bash%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              3 Answers
              3






              active

              oldest

              votes








              3 Answers
              3






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              2
              down vote



              accepted










              TL;DR



              In bash:



              readarray -t arr2 < <(git … )
              printf '%sn' "${arr2[@]}"




              There are two distinct problems on your question





              1. Shell splitting.

                When you did:



                arr1=($(git … ))


                the "command expansion" is unquoted, and so: it is subject to shell split and glob.



                The exactly see what that shell splitting do, use printf:



                $ printf '<%s>  '  $(echo word '"one simple sentence"')
                <word> <"one> <simple> <sentence">


                That would be avoided by quoting:



                $ printf '<%s>  '  "$(echo word '"one simple sentence"')"
                <word "one simple sentence">


                But that, also, would avoid the splitting on newlines that you want.




              2. Pipe

                When you executed:



                git … | … | … | readarray arr2


                The array variable arr2 got set but it went away when the pipe (|) was closed.



                You could use the value if you stay inside the last subshell:



                $ printf '%sn' "First value." "Second value." | 
                { readarray -t arr2; printf '%sn' "${arr2[@]}"; }
                First value.
                Second value.


                But the value of arr2 will not survive out of the pipe.




              Solution(s)



              You need to use read to split on newlines but not with a pipe.

              From older to newer:





              1. Loop.

                For old shells without arrays (using positional arguments, the only quasi-array):



                set --
                while IFS='' read -r value; do
                set -- "$@" "$value"
                done <<-EOT
                $(printf '%sn' "First value." "Second value.")
                EOT

                printf '%sn' "$@"


                To set an array (ksh, zsh, bash)



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done <<-EOT
                $(printf '%sn' "First value." "Second value.")
                EOT

                printf '%sn' "${arr1[@]}"



              2. Here-string

                Instead of the here document (<<) we can use a here-string (<<<):



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done <<<"$(printf '%sn' "First value." "Second value.")"

                printf '%sn' "${arr1[@]}"



              3. Process substitution

                In shells that support it (ksh, zsh, bash) you can use <( … ) to replace the here-string:



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done < <(printf '%sn' "First value." "Second value.")

                printf '%sn' "${arr1[@]}"


                With differences: <( ) is able to emit NUL bytes while a here-string might remove (or emit a warning) the NULs. A here-string adds a trailing newline by default. There may be others AFAIK.




              4. readarray

                Use readarray in bash[a] (a.k.a mapfile) to avoid the loop:



                readarray -t arr2 < <(printf '%sn' "First value." "Second value.")
                printf '%sn' "${arr2[@]}"





              [a]In ksh you will need to use read -A, which clears the variable before use, but needs some "magic" to split on newlines and read the whole input at once.



              IFS=$'n' read -d '' -A arr2 < <(printf '%sn' "First value." "Second value.")


              You will need to load a mapfile module in zsh to do something similar.






              share|improve this answer























              • Thank you so much for your clear answer. I have one question: You suggested a here-string (<<<"$(...)"), Jeff Schaller suggested using process substitution (< <(...)). Will there be a difference between the two, perhaps performance or spawning more processes? In the latter, will Bash still write to the temp file, and then read that back in, or will it be smart enough to directly pipe input from the git commands into readarray? If they both end up the same, I feel like < <(...) syntax looks cleaner, but I would rather not use that syntax if it actually creates and writes to a file.
                – vikarjramun
                Nov 30 at 22:45










              • All: <<< like << and <(…) use a temporary file so that commands that lseek their stdin can use them. Use any (in terms of speed or number of processes spawned).
                – Isaac
                Nov 30 at 22:56










              • Does piping also use a temporary file? If not, why doesn't <<< use the same mechanism as piping?
                – vikarjramun
                Nov 30 at 22:58










              • Does piping also use a temporary file? No. Don't know of any condition or shell that does. ……*why doesn't <<< use the same mechanism as piping?* That is a great question for a shell developer, or as a new question. I believe (personal opinion) that it got implemented as a sub-shell the first time around and that concept has worked well enough until now, no need to change? Legacy? You pick.
                – Isaac
                Nov 30 at 23:14










              • Okay, thanks again!
                – vikarjramun
                Nov 30 at 23:17















              up vote
              2
              down vote



              accepted










              TL;DR



              In bash:



              readarray -t arr2 < <(git … )
              printf '%sn' "${arr2[@]}"




              There are two distinct problems on your question





              1. Shell splitting.

                When you did:



                arr1=($(git … ))


                the "command expansion" is unquoted, and so: it is subject to shell split and glob.



                The exactly see what that shell splitting do, use printf:



                $ printf '<%s>  '  $(echo word '"one simple sentence"')
                <word> <"one> <simple> <sentence">


                That would be avoided by quoting:



                $ printf '<%s>  '  "$(echo word '"one simple sentence"')"
                <word "one simple sentence">


                But that, also, would avoid the splitting on newlines that you want.




              2. Pipe

                When you executed:



                git … | … | … | readarray arr2


                The array variable arr2 got set but it went away when the pipe (|) was closed.



                You could use the value if you stay inside the last subshell:



                $ printf '%sn' "First value." "Second value." | 
                { readarray -t arr2; printf '%sn' "${arr2[@]}"; }
                First value.
                Second value.


                But the value of arr2 will not survive out of the pipe.




              Solution(s)



              You need to use read to split on newlines but not with a pipe.

              From older to newer:





              1. Loop.

                For old shells without arrays (using positional arguments, the only quasi-array):



                set --
                while IFS='' read -r value; do
                set -- "$@" "$value"
                done <<-EOT
                $(printf '%sn' "First value." "Second value.")
                EOT

                printf '%sn' "$@"


                To set an array (ksh, zsh, bash)



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done <<-EOT
                $(printf '%sn' "First value." "Second value.")
                EOT

                printf '%sn' "${arr1[@]}"



              2. Here-string

                Instead of the here document (<<) we can use a here-string (<<<):



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done <<<"$(printf '%sn' "First value." "Second value.")"

                printf '%sn' "${arr1[@]}"



              3. Process substitution

                In shells that support it (ksh, zsh, bash) you can use <( … ) to replace the here-string:



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done < <(printf '%sn' "First value." "Second value.")

                printf '%sn' "${arr1[@]}"


                With differences: <( ) is able to emit NUL bytes while a here-string might remove (or emit a warning) the NULs. A here-string adds a trailing newline by default. There may be others AFAIK.




              4. readarray

                Use readarray in bash[a] (a.k.a mapfile) to avoid the loop:



                readarray -t arr2 < <(printf '%sn' "First value." "Second value.")
                printf '%sn' "${arr2[@]}"





              [a]In ksh you will need to use read -A, which clears the variable before use, but needs some "magic" to split on newlines and read the whole input at once.



              IFS=$'n' read -d '' -A arr2 < <(printf '%sn' "First value." "Second value.")


              You will need to load a mapfile module in zsh to do something similar.






              share|improve this answer























              • Thank you so much for your clear answer. I have one question: You suggested a here-string (<<<"$(...)"), Jeff Schaller suggested using process substitution (< <(...)). Will there be a difference between the two, perhaps performance or spawning more processes? In the latter, will Bash still write to the temp file, and then read that back in, or will it be smart enough to directly pipe input from the git commands into readarray? If they both end up the same, I feel like < <(...) syntax looks cleaner, but I would rather not use that syntax if it actually creates and writes to a file.
                – vikarjramun
                Nov 30 at 22:45










              • All: <<< like << and <(…) use a temporary file so that commands that lseek their stdin can use them. Use any (in terms of speed or number of processes spawned).
                – Isaac
                Nov 30 at 22:56










              • Does piping also use a temporary file? If not, why doesn't <<< use the same mechanism as piping?
                – vikarjramun
                Nov 30 at 22:58










              • Does piping also use a temporary file? No. Don't know of any condition or shell that does. ……*why doesn't <<< use the same mechanism as piping?* That is a great question for a shell developer, or as a new question. I believe (personal opinion) that it got implemented as a sub-shell the first time around and that concept has worked well enough until now, no need to change? Legacy? You pick.
                – Isaac
                Nov 30 at 23:14










              • Okay, thanks again!
                – vikarjramun
                Nov 30 at 23:17













              up vote
              2
              down vote



              accepted







              up vote
              2
              down vote



              accepted






              TL;DR



              In bash:



              readarray -t arr2 < <(git … )
              printf '%sn' "${arr2[@]}"




              There are two distinct problems on your question





              1. Shell splitting.

                When you did:



                arr1=($(git … ))


                the "command expansion" is unquoted, and so: it is subject to shell split and glob.



                The exactly see what that shell splitting do, use printf:



                $ printf '<%s>  '  $(echo word '"one simple sentence"')
                <word> <"one> <simple> <sentence">


                That would be avoided by quoting:



                $ printf '<%s>  '  "$(echo word '"one simple sentence"')"
                <word "one simple sentence">


                But that, also, would avoid the splitting on newlines that you want.




              2. Pipe

                When you executed:



                git … | … | … | readarray arr2


                The array variable arr2 got set but it went away when the pipe (|) was closed.



                You could use the value if you stay inside the last subshell:



                $ printf '%sn' "First value." "Second value." | 
                { readarray -t arr2; printf '%sn' "${arr2[@]}"; }
                First value.
                Second value.


                But the value of arr2 will not survive out of the pipe.




              Solution(s)



              You need to use read to split on newlines but not with a pipe.

              From older to newer:





              1. Loop.

                For old shells without arrays (using positional arguments, the only quasi-array):



                set --
                while IFS='' read -r value; do
                set -- "$@" "$value"
                done <<-EOT
                $(printf '%sn' "First value." "Second value.")
                EOT

                printf '%sn' "$@"


                To set an array (ksh, zsh, bash)



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done <<-EOT
                $(printf '%sn' "First value." "Second value.")
                EOT

                printf '%sn' "${arr1[@]}"



              2. Here-string

                Instead of the here document (<<) we can use a here-string (<<<):



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done <<<"$(printf '%sn' "First value." "Second value.")"

                printf '%sn' "${arr1[@]}"



              3. Process substitution

                In shells that support it (ksh, zsh, bash) you can use <( … ) to replace the here-string:



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done < <(printf '%sn' "First value." "Second value.")

                printf '%sn' "${arr1[@]}"


                With differences: <( ) is able to emit NUL bytes while a here-string might remove (or emit a warning) the NULs. A here-string adds a trailing newline by default. There may be others AFAIK.




              4. readarray

                Use readarray in bash[a] (a.k.a mapfile) to avoid the loop:



                readarray -t arr2 < <(printf '%sn' "First value." "Second value.")
                printf '%sn' "${arr2[@]}"





              [a]In ksh you will need to use read -A, which clears the variable before use, but needs some "magic" to split on newlines and read the whole input at once.



              IFS=$'n' read -d '' -A arr2 < <(printf '%sn' "First value." "Second value.")


              You will need to load a mapfile module in zsh to do something similar.






              share|improve this answer














              TL;DR



              In bash:



              readarray -t arr2 < <(git … )
              printf '%sn' "${arr2[@]}"




              There are two distinct problems on your question





              1. Shell splitting.

                When you did:



                arr1=($(git … ))


                the "command expansion" is unquoted, and so: it is subject to shell split and glob.



                The exactly see what that shell splitting do, use printf:



                $ printf '<%s>  '  $(echo word '"one simple sentence"')
                <word> <"one> <simple> <sentence">


                That would be avoided by quoting:



                $ printf '<%s>  '  "$(echo word '"one simple sentence"')"
                <word "one simple sentence">


                But that, also, would avoid the splitting on newlines that you want.




              2. Pipe

                When you executed:



                git … | … | … | readarray arr2


                The array variable arr2 got set but it went away when the pipe (|) was closed.



                You could use the value if you stay inside the last subshell:



                $ printf '%sn' "First value." "Second value." | 
                { readarray -t arr2; printf '%sn' "${arr2[@]}"; }
                First value.
                Second value.


                But the value of arr2 will not survive out of the pipe.




              Solution(s)



              You need to use read to split on newlines but not with a pipe.

              From older to newer:





              1. Loop.

                For old shells without arrays (using positional arguments, the only quasi-array):



                set --
                while IFS='' read -r value; do
                set -- "$@" "$value"
                done <<-EOT
                $(printf '%sn' "First value." "Second value.")
                EOT

                printf '%sn' "$@"


                To set an array (ksh, zsh, bash)



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done <<-EOT
                $(printf '%sn' "First value." "Second value.")
                EOT

                printf '%sn' "${arr1[@]}"



              2. Here-string

                Instead of the here document (<<) we can use a here-string (<<<):



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done <<<"$(printf '%sn' "First value." "Second value.")"

                printf '%sn' "${arr1[@]}"



              3. Process substitution

                In shells that support it (ksh, zsh, bash) you can use <( … ) to replace the here-string:



                i=0; arr1=()
                while IFS='' read -r value; do
                arr1+=("$value")
                done < <(printf '%sn' "First value." "Second value.")

                printf '%sn' "${arr1[@]}"


                With differences: <( ) is able to emit NUL bytes while a here-string might remove (or emit a warning) the NULs. A here-string adds a trailing newline by default. There may be others AFAIK.




              4. readarray

                Use readarray in bash[a] (a.k.a mapfile) to avoid the loop:



                readarray -t arr2 < <(printf '%sn' "First value." "Second value.")
                printf '%sn' "${arr2[@]}"





              [a]In ksh you will need to use read -A, which clears the variable before use, but needs some "magic" to split on newlines and read the whole input at once.



              IFS=$'n' read -d '' -A arr2 < <(printf '%sn' "First value." "Second value.")


              You will need to load a mapfile module in zsh to do something similar.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 30 at 23:17

























              answered Nov 30 at 21:26









              Isaac

              10.2k11446




              10.2k11446












              • Thank you so much for your clear answer. I have one question: You suggested a here-string (<<<"$(...)"), Jeff Schaller suggested using process substitution (< <(...)). Will there be a difference between the two, perhaps performance or spawning more processes? In the latter, will Bash still write to the temp file, and then read that back in, or will it be smart enough to directly pipe input from the git commands into readarray? If they both end up the same, I feel like < <(...) syntax looks cleaner, but I would rather not use that syntax if it actually creates and writes to a file.
                – vikarjramun
                Nov 30 at 22:45










              • All: <<< like << and <(…) use a temporary file so that commands that lseek their stdin can use them. Use any (in terms of speed or number of processes spawned).
                – Isaac
                Nov 30 at 22:56










              • Does piping also use a temporary file? If not, why doesn't <<< use the same mechanism as piping?
                – vikarjramun
                Nov 30 at 22:58










              • Does piping also use a temporary file? No. Don't know of any condition or shell that does. ……*why doesn't <<< use the same mechanism as piping?* That is a great question for a shell developer, or as a new question. I believe (personal opinion) that it got implemented as a sub-shell the first time around and that concept has worked well enough until now, no need to change? Legacy? You pick.
                – Isaac
                Nov 30 at 23:14










              • Okay, thanks again!
                – vikarjramun
                Nov 30 at 23:17


















              • Thank you so much for your clear answer. I have one question: You suggested a here-string (<<<"$(...)"), Jeff Schaller suggested using process substitution (< <(...)). Will there be a difference between the two, perhaps performance or spawning more processes? In the latter, will Bash still write to the temp file, and then read that back in, or will it be smart enough to directly pipe input from the git commands into readarray? If they both end up the same, I feel like < <(...) syntax looks cleaner, but I would rather not use that syntax if it actually creates and writes to a file.
                – vikarjramun
                Nov 30 at 22:45










              • All: <<< like << and <(…) use a temporary file so that commands that lseek their stdin can use them. Use any (in terms of speed or number of processes spawned).
                – Isaac
                Nov 30 at 22:56










              • Does piping also use a temporary file? If not, why doesn't <<< use the same mechanism as piping?
                – vikarjramun
                Nov 30 at 22:58










              • Does piping also use a temporary file? No. Don't know of any condition or shell that does. ……*why doesn't <<< use the same mechanism as piping?* That is a great question for a shell developer, or as a new question. I believe (personal opinion) that it got implemented as a sub-shell the first time around and that concept has worked well enough until now, no need to change? Legacy? You pick.
                – Isaac
                Nov 30 at 23:14










              • Okay, thanks again!
                – vikarjramun
                Nov 30 at 23:17
















              Thank you so much for your clear answer. I have one question: You suggested a here-string (<<<"$(...)"), Jeff Schaller suggested using process substitution (< <(...)). Will there be a difference between the two, perhaps performance or spawning more processes? In the latter, will Bash still write to the temp file, and then read that back in, or will it be smart enough to directly pipe input from the git commands into readarray? If they both end up the same, I feel like < <(...) syntax looks cleaner, but I would rather not use that syntax if it actually creates and writes to a file.
              – vikarjramun
              Nov 30 at 22:45




              Thank you so much for your clear answer. I have one question: You suggested a here-string (<<<"$(...)"), Jeff Schaller suggested using process substitution (< <(...)). Will there be a difference between the two, perhaps performance or spawning more processes? In the latter, will Bash still write to the temp file, and then read that back in, or will it be smart enough to directly pipe input from the git commands into readarray? If they both end up the same, I feel like < <(...) syntax looks cleaner, but I would rather not use that syntax if it actually creates and writes to a file.
              – vikarjramun
              Nov 30 at 22:45












              All: <<< like << and <(…) use a temporary file so that commands that lseek their stdin can use them. Use any (in terms of speed or number of processes spawned).
              – Isaac
              Nov 30 at 22:56




              All: <<< like << and <(…) use a temporary file so that commands that lseek their stdin can use them. Use any (in terms of speed or number of processes spawned).
              – Isaac
              Nov 30 at 22:56












              Does piping also use a temporary file? If not, why doesn't <<< use the same mechanism as piping?
              – vikarjramun
              Nov 30 at 22:58




              Does piping also use a temporary file? If not, why doesn't <<< use the same mechanism as piping?
              – vikarjramun
              Nov 30 at 22:58












              Does piping also use a temporary file? No. Don't know of any condition or shell that does. ……*why doesn't <<< use the same mechanism as piping?* That is a great question for a shell developer, or as a new question. I believe (personal opinion) that it got implemented as a sub-shell the first time around and that concept has worked well enough until now, no need to change? Legacy? You pick.
              – Isaac
              Nov 30 at 23:14




              Does piping also use a temporary file? No. Don't know of any condition or shell that does. ……*why doesn't <<< use the same mechanism as piping?* That is a great question for a shell developer, or as a new question. I believe (personal opinion) that it got implemented as a sub-shell the first time around and that concept has worked well enough until now, no need to change? Legacy? You pick.
              – Isaac
              Nov 30 at 23:14












              Okay, thanks again!
              – vikarjramun
              Nov 30 at 23:17




              Okay, thanks again!
              – vikarjramun
              Nov 30 at 23:17












              up vote
              2
              down vote













              When you piped to readarray, you started a subshell which correctly populated an arr2 array, but then exited. Use process substitution as the input to readarray:



              readarray -t arr2 < <(git ...)





              share|improve this answer

























                up vote
                2
                down vote













                When you piped to readarray, you started a subshell which correctly populated an arr2 array, but then exited. Use process substitution as the input to readarray:



                readarray -t arr2 < <(git ...)





                share|improve this answer























                  up vote
                  2
                  down vote










                  up vote
                  2
                  down vote









                  When you piped to readarray, you started a subshell which correctly populated an arr2 array, but then exited. Use process substitution as the input to readarray:



                  readarray -t arr2 < <(git ...)





                  share|improve this answer












                  When you piped to readarray, you started a subshell which correctly populated an arr2 array, but then exited. Use process substitution as the input to readarray:



                  readarray -t arr2 < <(git ...)






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 30 at 18:27









                  Jeff Schaller

                  37k1052121




                  37k1052121






















                      up vote
                      1
                      down vote













                      You are close



                      This is a "file names with space character" problem.



                      By default, the separator is the space character. It is the IFS environment variable that sets this.



                      To change temporarily your environment variable use this:



                      ifs_backup=$IFS
                      IFS=$(echo -en "nb")


                      Then your output for this command:



                      for a in "${arr1[@]}"; do echo "$a"; done


                      will be:



                      "Directory Name/File B.txt"
                      "File A.txt"


                      To restore IFS :



                      IFS=$ifs_backup





                      share|improve this answer

























                        up vote
                        1
                        down vote













                        You are close



                        This is a "file names with space character" problem.



                        By default, the separator is the space character. It is the IFS environment variable that sets this.



                        To change temporarily your environment variable use this:



                        ifs_backup=$IFS
                        IFS=$(echo -en "nb")


                        Then your output for this command:



                        for a in "${arr1[@]}"; do echo "$a"; done


                        will be:



                        "Directory Name/File B.txt"
                        "File A.txt"


                        To restore IFS :



                        IFS=$ifs_backup





                        share|improve this answer























                          up vote
                          1
                          down vote










                          up vote
                          1
                          down vote









                          You are close



                          This is a "file names with space character" problem.



                          By default, the separator is the space character. It is the IFS environment variable that sets this.



                          To change temporarily your environment variable use this:



                          ifs_backup=$IFS
                          IFS=$(echo -en "nb")


                          Then your output for this command:



                          for a in "${arr1[@]}"; do echo "$a"; done


                          will be:



                          "Directory Name/File B.txt"
                          "File A.txt"


                          To restore IFS :



                          IFS=$ifs_backup





                          share|improve this answer












                          You are close



                          This is a "file names with space character" problem.



                          By default, the separator is the space character. It is the IFS environment variable that sets this.



                          To change temporarily your environment variable use this:



                          ifs_backup=$IFS
                          IFS=$(echo -en "nb")


                          Then your output for this command:



                          for a in "${arr1[@]}"; do echo "$a"; done


                          will be:



                          "Directory Name/File B.txt"
                          "File A.txt"


                          To restore IFS :



                          IFS=$ifs_backup






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 30 at 18:27









                          lauhub

                          430616




                          430616






























                              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%2f485221%2fread-lines-into-array-one-element-per-line-using-bash%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