How to split a string into an array in bash Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) 2019 Community Moderator Election Results Why I closed the “Why is Kali so hard” questionHow to convert a String into Array in shell scriptHow to split command's output and assigns result to an array using only a single expression?Split: how to split into different percentages?String index processingSplit single string into character array using ONLY bashawk search for string containing forward slash in variablesplit a string into path and applicationBash: split multi line input into arrayUse sed to edit characters 65-79 if string is present in earlier positionBash Array Contains false positivesSplit string of filenames into an arrayHow do I split a string into two strings?

Is there a documented rationale why the House Ways and Means chairman can demand tax info?

Direct Experience of Meditation

What computer would be fastest for Mathematica Home Edition?

Slither Like a Snake

If I can make up priors, why can't I make up posteriors?

Fishing simulator

What are the performance impacts of 'functional' Rust?

Cold is to Refrigerator as warm is to?

How are presidential pardons supposed to be used?

Why don't the Weasley twins use magic outside of school if the Trace can only find the location of spells cast?

Is it possible to ask for a hotel room without minibar/extra services?

Replacing HDD with SSD; what about non-APFS/APFS?

I'm having difficulty getting my players to do stuff in a sandbox campaign

Strange behaviour of Check

What do you call a plan that's an alternative plan in case your initial plan fails?

Classification of bundles, Postnikov towers, obstruction theory, local coefficients

Need a suitable toxic chemical for a murder plot in my novel

Using "nakedly" instead of "with nothing on"

Estimated State payment too big --> money back; + 2018 Tax Reform

Who can trigger ship-wide alerts in Star Trek?

What is the electric potential inside a point charge?

How is simplicity better than precision and clarity in prose?

How should I respond to a player wanting to catch a sword between their hands?

Active filter with series inductor and resistor - do these exist?



How to split a string into an array in bash



Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)
2019 Community Moderator Election Results
Why I closed the “Why is Kali so hard” questionHow to convert a String into Array in shell scriptHow to split command's output and assigns result to an array using only a single expression?Split: how to split into different percentages?String index processingSplit single string into character array using ONLY bashawk search for string containing forward slash in variablesplit a string into path and applicationBash: split multi line input into arrayUse sed to edit characters 65-79 if string is present in earlier positionBash Array Contains false positivesSplit string of filenames into an arrayHow do I split a string into two strings?



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








6















I have a problem with the output of a program. I need to launch a command in bash and take its output (a string) and split it to add new lines in certain places. The string looks like this:



battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500


basically it is an xxx.yy.zz: value, but the value may contain spaces.
Here's the output I'd like to get



battery.charge: 90
battery.charge.low: 30
battery.runtime: 3690
battery.voltage: 230.0
device.mfr: MGE UPS SYSTEMS
device.model: Pulsar Evolution 500


I have an idea to search for first dot and then look back from that position for space to put a new line there, but I'm not sure how to achieve it in Bash.










share|improve this question






























    6















    I have a problem with the output of a program. I need to launch a command in bash and take its output (a string) and split it to add new lines in certain places. The string looks like this:



    battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500


    basically it is an xxx.yy.zz: value, but the value may contain spaces.
    Here's the output I'd like to get



    battery.charge: 90
    battery.charge.low: 30
    battery.runtime: 3690
    battery.voltage: 230.0
    device.mfr: MGE UPS SYSTEMS
    device.model: Pulsar Evolution 500


    I have an idea to search for first dot and then look back from that position for space to put a new line there, but I'm not sure how to achieve it in Bash.










    share|improve this question


























      6












      6








      6


      4






      I have a problem with the output of a program. I need to launch a command in bash and take its output (a string) and split it to add new lines in certain places. The string looks like this:



      battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500


      basically it is an xxx.yy.zz: value, but the value may contain spaces.
      Here's the output I'd like to get



      battery.charge: 90
      battery.charge.low: 30
      battery.runtime: 3690
      battery.voltage: 230.0
      device.mfr: MGE UPS SYSTEMS
      device.model: Pulsar Evolution 500


      I have an idea to search for first dot and then look back from that position for space to put a new line there, but I'm not sure how to achieve it in Bash.










      share|improve this question
















      I have a problem with the output of a program. I need to launch a command in bash and take its output (a string) and split it to add new lines in certain places. The string looks like this:



      battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500


      basically it is an xxx.yy.zz: value, but the value may contain spaces.
      Here's the output I'd like to get



      battery.charge: 90
      battery.charge.low: 30
      battery.runtime: 3690
      battery.voltage: 230.0
      device.mfr: MGE UPS SYSTEMS
      device.model: Pulsar Evolution 500


      I have an idea to search for first dot and then look back from that position for space to put a new line there, but I'm not sure how to achieve it in Bash.







      bash string split






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 17 hours ago









      Rui F Ribeiro

      42.1k1483142




      42.1k1483142










      asked May 13 '14 at 11:33









      user67524user67524

      33113




      33113




















          6 Answers
          6






          active

          oldest

          votes


















          2














          Pure bash solution, no external tools used to process the strings, just parameter expansion:



          #! /bin/bash
          str='battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500'

          IFS=: read -a fields <<< "$str"

          for (( i=0 ; i < $#fields[@] ; i++ )) ; do
          f=$fields[i]

          notfirst=$(( i>0 ))
          last=$(( i+1 == $#fields[@] ))

          (( notfirst )) && echo -n $f% *

          start=('' $'n' ' ')
          colon=('' ': ')
          echo -n "$start[notfirst + last]$f##* $colon[!last]"
          done
          echo


          Explanation: $notfirst and $last are booleans. The part before the last space $f% * isn't printed for the first field, as there is no such thing. $start and $colon hold various strings that separate the fields: at the first item, notfirst + last is 0, so nothing is prepended, for the rest of the lines, $notfirst is 1, so a newline is printed, and for the last line, the addition gives 2, so a space is printed. Then, the part after the last space is printed $f##* . Colon is printed for all lines except the last one.






          share|improve this answer

























          • Thanks a lot! I think I'll use your solution although I understand almost nothing. Can I ask you for some additions? Because original string begin with STRING: " and end with ". I forgot to mention that I need to remove them. It's constant 9 characters on the beginning and one char. from the end of the string.

            – user67524
            May 13 '14 at 21:12











          • @user67524: Read about Parameter Expansion in man bash. To remove the parts, use str=$str#STRING: "; str=$str%".

            – choroba
            May 13 '14 at 21:23



















          3














          A perl solution:



          $ perl -pe 'sS+:$seen++ ? "n$&" : "$&"ge' file
          battery.charge: 90
          battery.charge.low: 30
          battery.runtime: 3690
          battery.voltage: 230.0
          device.mfr: MGE UPS SYSTEMS
          device.model: Pulsar Evolution 500


          Explanation




          • S+: matches string end with :.

          • With all matched strings, we insert the newline before them ("n$&") except the first one ($seen++).





          share|improve this answer






























            3














            With GNU sed, you can match each contiguous string (i.e. without whitespace) terminated by : and then place a newline before all but the first one:



            sed 's/[^[:space:]]+:/n&/g2'


            If your version of sed does not support the gn extension, you can use a plain g modifier



            sed 's/[^[:space:]]1,:/
            &/g'


            which will work the same except for printing an additional newline before the first key. You could use perl -pe 's/S+:/n$&/g' with the same proviso (there may be a perl equivalent of the GNU sed g2 but I don't know it).






            share|improve this answer

























            • While you're at using GNU sed, you could also make it: sed -r 's/S+:/n&/g2'

              – Stéphane Chazelas
              May 13 '14 at 15:24


















            2














            It's easier using a tool that supports lookarounds:



            $ s="battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500"
            $ grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"
            battery.charge: 90
            battery.charge.low: 30
            battery.runtime: 3690
            battery.voltage: 230.0
            device.mfr: MGE UPS SYSTEMS
            device.model: Pulsar Evolution 500


            If you wanted the result in an array:



            $ IFS=$'n' foo=($(grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"))
            $ for i in "$!foo[@]"; do echo "$i<==>$foo[i]"; done
            0<==>battery.charge: 90
            1<==>battery.charge.low: 30
            2<==>battery.runtime: 3690
            3<==>battery.voltage: 230.0
            4<==>device.mfr: MGE UPS SYSTEMS
            5<==>device.model: Pulsar Evolution 500





            EDIT: Explanation of the regex:



            'S+:s+.*?(?=s+S+:|$)'



            • S+ matches one or more non-whitespace characters


            • : matches :


            • s+ matches one or more spaces after the :


            • .*? denotes a non-greedy match


            • (?=s+S+:|$) is a lookahead assertion to determine if there is:
              • one or more space followed by a string (non-whitespace charaters) and a colon, or

              • end of string


            So the string is split into parts like battery.charge: 90, ... device.mfr: MGE UPS SYSTEMS, ...




            Below are links to a couple of online regular expression analyzers:



            • http://rick.measham.id.au/paste/explain.pl

            • http://xenon.stanford.edu/~xusch/regexp/





            share|improve this answer

























            • +1 - very nice approach! If you can, please explain so that everyone understands what you're doing in the grep. This is a common problem in other Q's and a good explanation would be helpful here.

              – slm
              May 13 '14 at 13:38



















            1














            Here's a naive approach that should work assuming you don't care that tabs and newlines in the input (if any) are converted to plain spaces.



            The idea is simple: split the input on whitespace, and print every token except that you prepend tokens that end with : with a newline (and re-add a space in front of the others). The $count variable and related if are only useful to prevent an initial empty line. Could be removed if that's not a problem. (The script assumes the input is in a file called intput in the current directory.)



            #! /bin/bash

            count=0
            for i in $(<input) ; do
            fmt=
            if [[ $i =~ :$ ]] ; then
            if [[ $count -gt 0 ]] ; then
            fmt="n%s"
            else
            fmt="%s"
            fi
            ((count++))
            else
            fmt=" %s"
            fi
            printf "$fmt" "$i"
            done
            echo
            echo "Num items: $count"


            I hope someone can come up with a nicer alternative though.



            $ cat input
            battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
            $ ./t.sh
            battery.charge: 90
            battery.charge.low: 30
            battery.runtime: 3690
            battery.voltage: 230.0
            device.mfr: MGE UPS SYSTEMS
            device.model: Pulsar Evolution 500
            Num items: 6





            share|improve this answer






























              0














              You can use awk(1) with the following script split.awk:



              BEGIN RS=" "; first=1; 
              first first=0; printf "%s", $1; next;
              /[a-z]+.[^:]+:/ printf "n%s", $1; next;
              printf " %s", $1
              END printf "n"


              When you run



              awk -f split.awk input.dat


              you will get



              battery.charge: 90
              battery.charge.low: 30
              battery.runtime: 3690
              battery.voltage: 230.0
              device.mfr: MGE UPS SYSTEMS
              device.model: Pulsar Evolution 500


              The idea is to let awk split the input when it sees a space (setting record separator RS in line 1). Then it matches xxx.yy.zz: values in line 2 and 3 (distinguishing the very first match from subsequent ones), while line 4 matches whenever line 2 and 3 do not match. Line 5 just print the last newline.






              share|improve this answer























                Your Answer








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

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

                else
                createEditor();

                );

                function createEditor()
                StackExchange.prepareEditor(
                heartbeatType: 'answer',
                autoActivateHeartbeat: false,
                convertImagesToLinks: false,
                noModals: true,
                showLowRepImageUploadWarning: true,
                reputationToPostImages: null,
                bindNavPrevention: true,
                postfix: "",
                imageUploader:
                brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                allowUrls: true
                ,
                onDemand: true,
                discardSelector: ".discard-answer"
                ,immediatelyShowMarkdownHelp:true
                );



                );













                draft saved

                draft discarded


















                StackExchange.ready(
                function ()
                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f129191%2fhow-to-split-a-string-into-an-array-in-bash%23new-answer', 'question_page');

                );

                Post as a guest















                Required, but never shown

























                6 Answers
                6






                active

                oldest

                votes








                6 Answers
                6






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes









                2














                Pure bash solution, no external tools used to process the strings, just parameter expansion:



                #! /bin/bash
                str='battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500'

                IFS=: read -a fields <<< "$str"

                for (( i=0 ; i < $#fields[@] ; i++ )) ; do
                f=$fields[i]

                notfirst=$(( i>0 ))
                last=$(( i+1 == $#fields[@] ))

                (( notfirst )) && echo -n $f% *

                start=('' $'n' ' ')
                colon=('' ': ')
                echo -n "$start[notfirst + last]$f##* $colon[!last]"
                done
                echo


                Explanation: $notfirst and $last are booleans. The part before the last space $f% * isn't printed for the first field, as there is no such thing. $start and $colon hold various strings that separate the fields: at the first item, notfirst + last is 0, so nothing is prepended, for the rest of the lines, $notfirst is 1, so a newline is printed, and for the last line, the addition gives 2, so a space is printed. Then, the part after the last space is printed $f##* . Colon is printed for all lines except the last one.






                share|improve this answer

























                • Thanks a lot! I think I'll use your solution although I understand almost nothing. Can I ask you for some additions? Because original string begin with STRING: " and end with ". I forgot to mention that I need to remove them. It's constant 9 characters on the beginning and one char. from the end of the string.

                  – user67524
                  May 13 '14 at 21:12











                • @user67524: Read about Parameter Expansion in man bash. To remove the parts, use str=$str#STRING: "; str=$str%".

                  – choroba
                  May 13 '14 at 21:23
















                2














                Pure bash solution, no external tools used to process the strings, just parameter expansion:



                #! /bin/bash
                str='battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500'

                IFS=: read -a fields <<< "$str"

                for (( i=0 ; i < $#fields[@] ; i++ )) ; do
                f=$fields[i]

                notfirst=$(( i>0 ))
                last=$(( i+1 == $#fields[@] ))

                (( notfirst )) && echo -n $f% *

                start=('' $'n' ' ')
                colon=('' ': ')
                echo -n "$start[notfirst + last]$f##* $colon[!last]"
                done
                echo


                Explanation: $notfirst and $last are booleans. The part before the last space $f% * isn't printed for the first field, as there is no such thing. $start and $colon hold various strings that separate the fields: at the first item, notfirst + last is 0, so nothing is prepended, for the rest of the lines, $notfirst is 1, so a newline is printed, and for the last line, the addition gives 2, so a space is printed. Then, the part after the last space is printed $f##* . Colon is printed for all lines except the last one.






                share|improve this answer

























                • Thanks a lot! I think I'll use your solution although I understand almost nothing. Can I ask you for some additions? Because original string begin with STRING: " and end with ". I forgot to mention that I need to remove them. It's constant 9 characters on the beginning and one char. from the end of the string.

                  – user67524
                  May 13 '14 at 21:12











                • @user67524: Read about Parameter Expansion in man bash. To remove the parts, use str=$str#STRING: "; str=$str%".

                  – choroba
                  May 13 '14 at 21:23














                2












                2








                2







                Pure bash solution, no external tools used to process the strings, just parameter expansion:



                #! /bin/bash
                str='battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500'

                IFS=: read -a fields <<< "$str"

                for (( i=0 ; i < $#fields[@] ; i++ )) ; do
                f=$fields[i]

                notfirst=$(( i>0 ))
                last=$(( i+1 == $#fields[@] ))

                (( notfirst )) && echo -n $f% *

                start=('' $'n' ' ')
                colon=('' ': ')
                echo -n "$start[notfirst + last]$f##* $colon[!last]"
                done
                echo


                Explanation: $notfirst and $last are booleans. The part before the last space $f% * isn't printed for the first field, as there is no such thing. $start and $colon hold various strings that separate the fields: at the first item, notfirst + last is 0, so nothing is prepended, for the rest of the lines, $notfirst is 1, so a newline is printed, and for the last line, the addition gives 2, so a space is printed. Then, the part after the last space is printed $f##* . Colon is printed for all lines except the last one.






                share|improve this answer















                Pure bash solution, no external tools used to process the strings, just parameter expansion:



                #! /bin/bash
                str='battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500'

                IFS=: read -a fields <<< "$str"

                for (( i=0 ; i < $#fields[@] ; i++ )) ; do
                f=$fields[i]

                notfirst=$(( i>0 ))
                last=$(( i+1 == $#fields[@] ))

                (( notfirst )) && echo -n $f% *

                start=('' $'n' ' ')
                colon=('' ': ')
                echo -n "$start[notfirst + last]$f##* $colon[!last]"
                done
                echo


                Explanation: $notfirst and $last are booleans. The part before the last space $f% * isn't printed for the first field, as there is no such thing. $start and $colon hold various strings that separate the fields: at the first item, notfirst + last is 0, so nothing is prepended, for the rest of the lines, $notfirst is 1, so a newline is printed, and for the last line, the addition gives 2, so a space is printed. Then, the part after the last space is printed $f##* . Colon is printed for all lines except the last one.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited May 13 '14 at 21:28

























                answered May 13 '14 at 11:58









                chorobachoroba

                27.1k45176




                27.1k45176












                • Thanks a lot! I think I'll use your solution although I understand almost nothing. Can I ask you for some additions? Because original string begin with STRING: " and end with ". I forgot to mention that I need to remove them. It's constant 9 characters on the beginning and one char. from the end of the string.

                  – user67524
                  May 13 '14 at 21:12











                • @user67524: Read about Parameter Expansion in man bash. To remove the parts, use str=$str#STRING: "; str=$str%".

                  – choroba
                  May 13 '14 at 21:23


















                • Thanks a lot! I think I'll use your solution although I understand almost nothing. Can I ask you for some additions? Because original string begin with STRING: " and end with ". I forgot to mention that I need to remove them. It's constant 9 characters on the beginning and one char. from the end of the string.

                  – user67524
                  May 13 '14 at 21:12











                • @user67524: Read about Parameter Expansion in man bash. To remove the parts, use str=$str#STRING: "; str=$str%".

                  – choroba
                  May 13 '14 at 21:23

















                Thanks a lot! I think I'll use your solution although I understand almost nothing. Can I ask you for some additions? Because original string begin with STRING: " and end with ". I forgot to mention that I need to remove them. It's constant 9 characters on the beginning and one char. from the end of the string.

                – user67524
                May 13 '14 at 21:12





                Thanks a lot! I think I'll use your solution although I understand almost nothing. Can I ask you for some additions? Because original string begin with STRING: " and end with ". I forgot to mention that I need to remove them. It's constant 9 characters on the beginning and one char. from the end of the string.

                – user67524
                May 13 '14 at 21:12













                @user67524: Read about Parameter Expansion in man bash. To remove the parts, use str=$str#STRING: "; str=$str%".

                – choroba
                May 13 '14 at 21:23






                @user67524: Read about Parameter Expansion in man bash. To remove the parts, use str=$str#STRING: "; str=$str%".

                – choroba
                May 13 '14 at 21:23














                3














                A perl solution:



                $ perl -pe 'sS+:$seen++ ? "n$&" : "$&"ge' file
                battery.charge: 90
                battery.charge.low: 30
                battery.runtime: 3690
                battery.voltage: 230.0
                device.mfr: MGE UPS SYSTEMS
                device.model: Pulsar Evolution 500


                Explanation




                • S+: matches string end with :.

                • With all matched strings, we insert the newline before them ("n$&") except the first one ($seen++).





                share|improve this answer



























                  3














                  A perl solution:



                  $ perl -pe 'sS+:$seen++ ? "n$&" : "$&"ge' file
                  battery.charge: 90
                  battery.charge.low: 30
                  battery.runtime: 3690
                  battery.voltage: 230.0
                  device.mfr: MGE UPS SYSTEMS
                  device.model: Pulsar Evolution 500


                  Explanation




                  • S+: matches string end with :.

                  • With all matched strings, we insert the newline before them ("n$&") except the first one ($seen++).





                  share|improve this answer

























                    3












                    3








                    3







                    A perl solution:



                    $ perl -pe 'sS+:$seen++ ? "n$&" : "$&"ge' file
                    battery.charge: 90
                    battery.charge.low: 30
                    battery.runtime: 3690
                    battery.voltage: 230.0
                    device.mfr: MGE UPS SYSTEMS
                    device.model: Pulsar Evolution 500


                    Explanation




                    • S+: matches string end with :.

                    • With all matched strings, we insert the newline before them ("n$&") except the first one ($seen++).





                    share|improve this answer













                    A perl solution:



                    $ perl -pe 'sS+:$seen++ ? "n$&" : "$&"ge' file
                    battery.charge: 90
                    battery.charge.low: 30
                    battery.runtime: 3690
                    battery.voltage: 230.0
                    device.mfr: MGE UPS SYSTEMS
                    device.model: Pulsar Evolution 500


                    Explanation




                    • S+: matches string end with :.

                    • With all matched strings, we insert the newline before them ("n$&") except the first one ($seen++).






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered May 13 '14 at 14:16









                    cuonglmcuonglm

                    106k25211309




                    106k25211309





















                        3














                        With GNU sed, you can match each contiguous string (i.e. without whitespace) terminated by : and then place a newline before all but the first one:



                        sed 's/[^[:space:]]+:/n&/g2'


                        If your version of sed does not support the gn extension, you can use a plain g modifier



                        sed 's/[^[:space:]]1,:/
                        &/g'


                        which will work the same except for printing an additional newline before the first key. You could use perl -pe 's/S+:/n$&/g' with the same proviso (there may be a perl equivalent of the GNU sed g2 but I don't know it).






                        share|improve this answer

























                        • While you're at using GNU sed, you could also make it: sed -r 's/S+:/n&/g2'

                          – Stéphane Chazelas
                          May 13 '14 at 15:24















                        3














                        With GNU sed, you can match each contiguous string (i.e. without whitespace) terminated by : and then place a newline before all but the first one:



                        sed 's/[^[:space:]]+:/n&/g2'


                        If your version of sed does not support the gn extension, you can use a plain g modifier



                        sed 's/[^[:space:]]1,:/
                        &/g'


                        which will work the same except for printing an additional newline before the first key. You could use perl -pe 's/S+:/n$&/g' with the same proviso (there may be a perl equivalent of the GNU sed g2 but I don't know it).






                        share|improve this answer

























                        • While you're at using GNU sed, you could also make it: sed -r 's/S+:/n&/g2'

                          – Stéphane Chazelas
                          May 13 '14 at 15:24













                        3












                        3








                        3







                        With GNU sed, you can match each contiguous string (i.e. without whitespace) terminated by : and then place a newline before all but the first one:



                        sed 's/[^[:space:]]+:/n&/g2'


                        If your version of sed does not support the gn extension, you can use a plain g modifier



                        sed 's/[^[:space:]]1,:/
                        &/g'


                        which will work the same except for printing an additional newline before the first key. You could use perl -pe 's/S+:/n$&/g' with the same proviso (there may be a perl equivalent of the GNU sed g2 but I don't know it).






                        share|improve this answer















                        With GNU sed, you can match each contiguous string (i.e. without whitespace) terminated by : and then place a newline before all but the first one:



                        sed 's/[^[:space:]]+:/n&/g2'


                        If your version of sed does not support the gn extension, you can use a plain g modifier



                        sed 's/[^[:space:]]1,:/
                        &/g'


                        which will work the same except for printing an additional newline before the first key. You could use perl -pe 's/S+:/n$&/g' with the same proviso (there may be a perl equivalent of the GNU sed g2 but I don't know it).







                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited May 13 '14 at 15:29









                        Stéphane Chazelas

                        314k57594953




                        314k57594953










                        answered May 13 '14 at 12:35









                        steeldriversteeldriver

                        37.8k45489




                        37.8k45489












                        • While you're at using GNU sed, you could also make it: sed -r 's/S+:/n&/g2'

                          – Stéphane Chazelas
                          May 13 '14 at 15:24

















                        • While you're at using GNU sed, you could also make it: sed -r 's/S+:/n&/g2'

                          – Stéphane Chazelas
                          May 13 '14 at 15:24
















                        While you're at using GNU sed, you could also make it: sed -r 's/S+:/n&/g2'

                        – Stéphane Chazelas
                        May 13 '14 at 15:24





                        While you're at using GNU sed, you could also make it: sed -r 's/S+:/n&/g2'

                        – Stéphane Chazelas
                        May 13 '14 at 15:24











                        2














                        It's easier using a tool that supports lookarounds:



                        $ s="battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500"
                        $ grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"
                        battery.charge: 90
                        battery.charge.low: 30
                        battery.runtime: 3690
                        battery.voltage: 230.0
                        device.mfr: MGE UPS SYSTEMS
                        device.model: Pulsar Evolution 500


                        If you wanted the result in an array:



                        $ IFS=$'n' foo=($(grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"))
                        $ for i in "$!foo[@]"; do echo "$i<==>$foo[i]"; done
                        0<==>battery.charge: 90
                        1<==>battery.charge.low: 30
                        2<==>battery.runtime: 3690
                        3<==>battery.voltage: 230.0
                        4<==>device.mfr: MGE UPS SYSTEMS
                        5<==>device.model: Pulsar Evolution 500





                        EDIT: Explanation of the regex:



                        'S+:s+.*?(?=s+S+:|$)'



                        • S+ matches one or more non-whitespace characters


                        • : matches :


                        • s+ matches one or more spaces after the :


                        • .*? denotes a non-greedy match


                        • (?=s+S+:|$) is a lookahead assertion to determine if there is:
                          • one or more space followed by a string (non-whitespace charaters) and a colon, or

                          • end of string


                        So the string is split into parts like battery.charge: 90, ... device.mfr: MGE UPS SYSTEMS, ...




                        Below are links to a couple of online regular expression analyzers:



                        • http://rick.measham.id.au/paste/explain.pl

                        • http://xenon.stanford.edu/~xusch/regexp/





                        share|improve this answer

























                        • +1 - very nice approach! If you can, please explain so that everyone understands what you're doing in the grep. This is a common problem in other Q's and a good explanation would be helpful here.

                          – slm
                          May 13 '14 at 13:38
















                        2














                        It's easier using a tool that supports lookarounds:



                        $ s="battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500"
                        $ grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"
                        battery.charge: 90
                        battery.charge.low: 30
                        battery.runtime: 3690
                        battery.voltage: 230.0
                        device.mfr: MGE UPS SYSTEMS
                        device.model: Pulsar Evolution 500


                        If you wanted the result in an array:



                        $ IFS=$'n' foo=($(grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"))
                        $ for i in "$!foo[@]"; do echo "$i<==>$foo[i]"; done
                        0<==>battery.charge: 90
                        1<==>battery.charge.low: 30
                        2<==>battery.runtime: 3690
                        3<==>battery.voltage: 230.0
                        4<==>device.mfr: MGE UPS SYSTEMS
                        5<==>device.model: Pulsar Evolution 500





                        EDIT: Explanation of the regex:



                        'S+:s+.*?(?=s+S+:|$)'



                        • S+ matches one or more non-whitespace characters


                        • : matches :


                        • s+ matches one or more spaces after the :


                        • .*? denotes a non-greedy match


                        • (?=s+S+:|$) is a lookahead assertion to determine if there is:
                          • one or more space followed by a string (non-whitespace charaters) and a colon, or

                          • end of string


                        So the string is split into parts like battery.charge: 90, ... device.mfr: MGE UPS SYSTEMS, ...




                        Below are links to a couple of online regular expression analyzers:



                        • http://rick.measham.id.au/paste/explain.pl

                        • http://xenon.stanford.edu/~xusch/regexp/





                        share|improve this answer

























                        • +1 - very nice approach! If you can, please explain so that everyone understands what you're doing in the grep. This is a common problem in other Q's and a good explanation would be helpful here.

                          – slm
                          May 13 '14 at 13:38














                        2












                        2








                        2







                        It's easier using a tool that supports lookarounds:



                        $ s="battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500"
                        $ grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"
                        battery.charge: 90
                        battery.charge.low: 30
                        battery.runtime: 3690
                        battery.voltage: 230.0
                        device.mfr: MGE UPS SYSTEMS
                        device.model: Pulsar Evolution 500


                        If you wanted the result in an array:



                        $ IFS=$'n' foo=($(grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"))
                        $ for i in "$!foo[@]"; do echo "$i<==>$foo[i]"; done
                        0<==>battery.charge: 90
                        1<==>battery.charge.low: 30
                        2<==>battery.runtime: 3690
                        3<==>battery.voltage: 230.0
                        4<==>device.mfr: MGE UPS SYSTEMS
                        5<==>device.model: Pulsar Evolution 500





                        EDIT: Explanation of the regex:



                        'S+:s+.*?(?=s+S+:|$)'



                        • S+ matches one or more non-whitespace characters


                        • : matches :


                        • s+ matches one or more spaces after the :


                        • .*? denotes a non-greedy match


                        • (?=s+S+:|$) is a lookahead assertion to determine if there is:
                          • one or more space followed by a string (non-whitespace charaters) and a colon, or

                          • end of string


                        So the string is split into parts like battery.charge: 90, ... device.mfr: MGE UPS SYSTEMS, ...




                        Below are links to a couple of online regular expression analyzers:



                        • http://rick.measham.id.au/paste/explain.pl

                        • http://xenon.stanford.edu/~xusch/regexp/





                        share|improve this answer















                        It's easier using a tool that supports lookarounds:



                        $ s="battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500"
                        $ grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"
                        battery.charge: 90
                        battery.charge.low: 30
                        battery.runtime: 3690
                        battery.voltage: 230.0
                        device.mfr: MGE UPS SYSTEMS
                        device.model: Pulsar Evolution 500


                        If you wanted the result in an array:



                        $ IFS=$'n' foo=($(grep -oP 'S+:s+.*?(?=s+S+:|$)' <<< "$s"))
                        $ for i in "$!foo[@]"; do echo "$i<==>$foo[i]"; done
                        0<==>battery.charge: 90
                        1<==>battery.charge.low: 30
                        2<==>battery.runtime: 3690
                        3<==>battery.voltage: 230.0
                        4<==>device.mfr: MGE UPS SYSTEMS
                        5<==>device.model: Pulsar Evolution 500





                        EDIT: Explanation of the regex:



                        'S+:s+.*?(?=s+S+:|$)'



                        • S+ matches one or more non-whitespace characters


                        • : matches :


                        • s+ matches one or more spaces after the :


                        • .*? denotes a non-greedy match


                        • (?=s+S+:|$) is a lookahead assertion to determine if there is:
                          • one or more space followed by a string (non-whitespace charaters) and a colon, or

                          • end of string


                        So the string is split into parts like battery.charge: 90, ... device.mfr: MGE UPS SYSTEMS, ...




                        Below are links to a couple of online regular expression analyzers:



                        • http://rick.measham.id.au/paste/explain.pl

                        • http://xenon.stanford.edu/~xusch/regexp/






                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited May 13 '14 at 14:24

























                        answered May 13 '14 at 12:38









                        devnulldevnull

                        8,73113042




                        8,73113042












                        • +1 - very nice approach! If you can, please explain so that everyone understands what you're doing in the grep. This is a common problem in other Q's and a good explanation would be helpful here.

                          – slm
                          May 13 '14 at 13:38


















                        • +1 - very nice approach! If you can, please explain so that everyone understands what you're doing in the grep. This is a common problem in other Q's and a good explanation would be helpful here.

                          – slm
                          May 13 '14 at 13:38

















                        +1 - very nice approach! If you can, please explain so that everyone understands what you're doing in the grep. This is a common problem in other Q's and a good explanation would be helpful here.

                        – slm
                        May 13 '14 at 13:38






                        +1 - very nice approach! If you can, please explain so that everyone understands what you're doing in the grep. This is a common problem in other Q's and a good explanation would be helpful here.

                        – slm
                        May 13 '14 at 13:38












                        1














                        Here's a naive approach that should work assuming you don't care that tabs and newlines in the input (if any) are converted to plain spaces.



                        The idea is simple: split the input on whitespace, and print every token except that you prepend tokens that end with : with a newline (and re-add a space in front of the others). The $count variable and related if are only useful to prevent an initial empty line. Could be removed if that's not a problem. (The script assumes the input is in a file called intput in the current directory.)



                        #! /bin/bash

                        count=0
                        for i in $(<input) ; do
                        fmt=
                        if [[ $i =~ :$ ]] ; then
                        if [[ $count -gt 0 ]] ; then
                        fmt="n%s"
                        else
                        fmt="%s"
                        fi
                        ((count++))
                        else
                        fmt=" %s"
                        fi
                        printf "$fmt" "$i"
                        done
                        echo
                        echo "Num items: $count"


                        I hope someone can come up with a nicer alternative though.



                        $ cat input
                        battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
                        $ ./t.sh
                        battery.charge: 90
                        battery.charge.low: 30
                        battery.runtime: 3690
                        battery.voltage: 230.0
                        device.mfr: MGE UPS SYSTEMS
                        device.model: Pulsar Evolution 500
                        Num items: 6





                        share|improve this answer



























                          1














                          Here's a naive approach that should work assuming you don't care that tabs and newlines in the input (if any) are converted to plain spaces.



                          The idea is simple: split the input on whitespace, and print every token except that you prepend tokens that end with : with a newline (and re-add a space in front of the others). The $count variable and related if are only useful to prevent an initial empty line. Could be removed if that's not a problem. (The script assumes the input is in a file called intput in the current directory.)



                          #! /bin/bash

                          count=0
                          for i in $(<input) ; do
                          fmt=
                          if [[ $i =~ :$ ]] ; then
                          if [[ $count -gt 0 ]] ; then
                          fmt="n%s"
                          else
                          fmt="%s"
                          fi
                          ((count++))
                          else
                          fmt=" %s"
                          fi
                          printf "$fmt" "$i"
                          done
                          echo
                          echo "Num items: $count"


                          I hope someone can come up with a nicer alternative though.



                          $ cat input
                          battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
                          $ ./t.sh
                          battery.charge: 90
                          battery.charge.low: 30
                          battery.runtime: 3690
                          battery.voltage: 230.0
                          device.mfr: MGE UPS SYSTEMS
                          device.model: Pulsar Evolution 500
                          Num items: 6





                          share|improve this answer

























                            1












                            1








                            1







                            Here's a naive approach that should work assuming you don't care that tabs and newlines in the input (if any) are converted to plain spaces.



                            The idea is simple: split the input on whitespace, and print every token except that you prepend tokens that end with : with a newline (and re-add a space in front of the others). The $count variable and related if are only useful to prevent an initial empty line. Could be removed if that's not a problem. (The script assumes the input is in a file called intput in the current directory.)



                            #! /bin/bash

                            count=0
                            for i in $(<input) ; do
                            fmt=
                            if [[ $i =~ :$ ]] ; then
                            if [[ $count -gt 0 ]] ; then
                            fmt="n%s"
                            else
                            fmt="%s"
                            fi
                            ((count++))
                            else
                            fmt=" %s"
                            fi
                            printf "$fmt" "$i"
                            done
                            echo
                            echo "Num items: $count"


                            I hope someone can come up with a nicer alternative though.



                            $ cat input
                            battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
                            $ ./t.sh
                            battery.charge: 90
                            battery.charge.low: 30
                            battery.runtime: 3690
                            battery.voltage: 230.0
                            device.mfr: MGE UPS SYSTEMS
                            device.model: Pulsar Evolution 500
                            Num items: 6





                            share|improve this answer













                            Here's a naive approach that should work assuming you don't care that tabs and newlines in the input (if any) are converted to plain spaces.



                            The idea is simple: split the input on whitespace, and print every token except that you prepend tokens that end with : with a newline (and re-add a space in front of the others). The $count variable and related if are only useful to prevent an initial empty line. Could be removed if that's not a problem. (The script assumes the input is in a file called intput in the current directory.)



                            #! /bin/bash

                            count=0
                            for i in $(<input) ; do
                            fmt=
                            if [[ $i =~ :$ ]] ; then
                            if [[ $count -gt 0 ]] ; then
                            fmt="n%s"
                            else
                            fmt="%s"
                            fi
                            ((count++))
                            else
                            fmt=" %s"
                            fi
                            printf "$fmt" "$i"
                            done
                            echo
                            echo "Num items: $count"


                            I hope someone can come up with a nicer alternative though.



                            $ cat input
                            battery.charge: 90 battery.charge.low: 30 battery.runtime: 3690 battery.voltage: 230.0 device.mfr: MGE UPS SYSTEMS device.model: Pulsar Evolution 500
                            $ ./t.sh
                            battery.charge: 90
                            battery.charge.low: 30
                            battery.runtime: 3690
                            battery.voltage: 230.0
                            device.mfr: MGE UPS SYSTEMS
                            device.model: Pulsar Evolution 500
                            Num items: 6






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered May 13 '14 at 12:28









                            MatMat

                            40k8124128




                            40k8124128





















                                0














                                You can use awk(1) with the following script split.awk:



                                BEGIN RS=" "; first=1; 
                                first first=0; printf "%s", $1; next;
                                /[a-z]+.[^:]+:/ printf "n%s", $1; next;
                                printf " %s", $1
                                END printf "n"


                                When you run



                                awk -f split.awk input.dat


                                you will get



                                battery.charge: 90
                                battery.charge.low: 30
                                battery.runtime: 3690
                                battery.voltage: 230.0
                                device.mfr: MGE UPS SYSTEMS
                                device.model: Pulsar Evolution 500


                                The idea is to let awk split the input when it sees a space (setting record separator RS in line 1). Then it matches xxx.yy.zz: values in line 2 and 3 (distinguishing the very first match from subsequent ones), while line 4 matches whenever line 2 and 3 do not match. Line 5 just print the last newline.






                                share|improve this answer



























                                  0














                                  You can use awk(1) with the following script split.awk:



                                  BEGIN RS=" "; first=1; 
                                  first first=0; printf "%s", $1; next;
                                  /[a-z]+.[^:]+:/ printf "n%s", $1; next;
                                  printf " %s", $1
                                  END printf "n"


                                  When you run



                                  awk -f split.awk input.dat


                                  you will get



                                  battery.charge: 90
                                  battery.charge.low: 30
                                  battery.runtime: 3690
                                  battery.voltage: 230.0
                                  device.mfr: MGE UPS SYSTEMS
                                  device.model: Pulsar Evolution 500


                                  The idea is to let awk split the input when it sees a space (setting record separator RS in line 1). Then it matches xxx.yy.zz: values in line 2 and 3 (distinguishing the very first match from subsequent ones), while line 4 matches whenever line 2 and 3 do not match. Line 5 just print the last newline.






                                  share|improve this answer

























                                    0












                                    0








                                    0







                                    You can use awk(1) with the following script split.awk:



                                    BEGIN RS=" "; first=1; 
                                    first first=0; printf "%s", $1; next;
                                    /[a-z]+.[^:]+:/ printf "n%s", $1; next;
                                    printf " %s", $1
                                    END printf "n"


                                    When you run



                                    awk -f split.awk input.dat


                                    you will get



                                    battery.charge: 90
                                    battery.charge.low: 30
                                    battery.runtime: 3690
                                    battery.voltage: 230.0
                                    device.mfr: MGE UPS SYSTEMS
                                    device.model: Pulsar Evolution 500


                                    The idea is to let awk split the input when it sees a space (setting record separator RS in line 1). Then it matches xxx.yy.zz: values in line 2 and 3 (distinguishing the very first match from subsequent ones), while line 4 matches whenever line 2 and 3 do not match. Line 5 just print the last newline.






                                    share|improve this answer













                                    You can use awk(1) with the following script split.awk:



                                    BEGIN RS=" "; first=1; 
                                    first first=0; printf "%s", $1; next;
                                    /[a-z]+.[^:]+:/ printf "n%s", $1; next;
                                    printf " %s", $1
                                    END printf "n"


                                    When you run



                                    awk -f split.awk input.dat


                                    you will get



                                    battery.charge: 90
                                    battery.charge.low: 30
                                    battery.runtime: 3690
                                    battery.voltage: 230.0
                                    device.mfr: MGE UPS SYSTEMS
                                    device.model: Pulsar Evolution 500


                                    The idea is to let awk split the input when it sees a space (setting record separator RS in line 1). Then it matches xxx.yy.zz: values in line 2 and 3 (distinguishing the very first match from subsequent ones), while line 4 matches whenever line 2 and 3 do not match. Line 5 just print the last newline.







                                    share|improve this answer












                                    share|improve this answer



                                    share|improve this answer










                                    answered May 13 '14 at 12:39









                                    tkrennwatkrennwa

                                    2,64511013




                                    2,64511013



























                                        draft saved

                                        draft discarded
















































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


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

                                        But avoid


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

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

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




                                        draft saved


                                        draft discarded














                                        StackExchange.ready(
                                        function ()
                                        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f129191%2fhow-to-split-a-string-into-an-array-in-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







                                        -bash, split, string

                                        Popular posts from this blog

                                        Frič See also Navigation menuinternal link

                                        Identify plant with long narrow paired leaves and reddish stems Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) Announcing the arrival of Valued Associate #679: Cesar Manara Unicorn Meta Zoo #1: Why another podcast?What is this plant with long sharp leaves? Is it a weed?What is this 3ft high, stalky plant, with mid sized narrow leaves?What is this young shrub with opposite ovate, crenate leaves and reddish stems?What is this plant with large broad serrated leaves?Identify this upright branching weed with long leaves and reddish stemsPlease help me identify this bulbous plant with long, broad leaves and white flowersWhat is this small annual with narrow gray/green leaves and rust colored daisy-type flowers?What is this chilli plant?Does anyone know what type of chilli plant this is?Help identify this plant

                                        fontconfig warning: “/etc/fonts/fonts.conf”, line 100: unknown “element blank” The 2019 Stack Overflow Developer Survey Results Are In“tar: unrecognized option --warning” during 'apt-get install'How to fix Fontconfig errorHow do I figure out which font file is chosen for a system generic font alias?Why are some apt-get-installed fonts being ignored by fc-list, xfontsel, etc?Reload settings in /etc/fonts/conf.dTaking 30 seconds longer to boot after upgrade from jessie to stretchHow to match multiple font names with a single <match> element?Adding a custom font to fontconfigRemoving fonts from fontconfig <match> resultsBroken fonts after upgrading Firefox ESR to latest Firefox