1

I've got a string like this:

8080 "ac ac df asd" 9019 "f v adfs" 1 "123 da 123x" 

Is there a clever way to convert this into arrays like this using Bash?

8080 "ac ac df asd" 9019 "f v adfs" 1 "123 da 123x" 
2
  • Each entry in the array will have exactly two items as shown?
    – John
    CommentedJul 10, 2015 at 12:10
  • Yes, it always will
    – shomel
    CommentedJul 10, 2015 at 12:14

3 Answers 3

1
# define function foo() { while [ -n "$2" ]; do array+=( "\"$1\" \"$2\"" ); shift 2; done; } # call function with string foo 8080 "ac ac df asd" 9019 "f v adfs" 1 "123 da 123x" # print array printf "%s\n" "${array[@]}" 

Output:

 "8080" "ac ac df asd" "9019" "f v adfs" "1" "123 da 123x" 
    1

    I think this is what you want, assuming it's OK to use sed.

    Example

    $ echo '8080 "ac ac df asd" 9019 "f v adfs" 1 "123 da 123x"' | sed 's/" \([0-9]\)/"\n\1/g' 8080 "ac ac df asd" 9019 "f v adfs" 1 "123 da 123x" 

    The approach you're looking for is to recognize a pattern and replace it with a newline character, \n. The pattern that we're recognizing with sed is an quote followed by a space, followed by a digit.

    " ...digit... 

    In those situations we want to put a \n after the " + space. Given the space will now occur at the end of the line, we can drop it, hence this, "\n\1. NOTE: The \1 is a variable that we saved the digit in when we did this on the matching side in our s/..match../..replace../g in sed, i.e. \([0-9]\). You can save pieces of strings in sed when you wrap them with escaped parens, \(..save this..\).

      1

      This will split your values into separate array items, which you can then join. I'm sure there's a better way but this delivers the output you've requested from the input you've provided. If this is user input (or if it's input outside your control) the following solution should not be used in case backticks or variable substitutions are offered to the eval.

      s='8080 "ac ac df asd" 9019 "f v adfs" 1 "123 da 123x"' eval t=("$s") # Incautious array assignment a=() for k in $(seq 0 $(( (${#t[@]}+1) /2 -1 )) ) # Count pairs of elements do p1=$((k*2)) p2=$((k*2 +1)) # Indexes into original list a+=("${t[$p1]} \"${t[$p2]}\"") # New element is a pair of originals done for p in "${a[@]}" # Report elements of array a[] do echo "item> $p" >&2 done 

      This code assumes that the second of each pair requires quotes (they are removed during the eval). You could perhaps make that more clever by adding quotes around a value only if that value contained whitespace, but I haven't done that here.

      2
      • This only seems to work for the 1st 4 elements. You're missing the 1 "123 da 123x".
        – terdon
        CommentedJul 20, 2015 at 18:22
      • @terdon thank you. I'd written ${#t} instead of ${#t[@]} so was counting the length of $t[0] instead of the number of elements in the array $t. Code updated.CommentedJul 20, 2015 at 20:14

      You must log in to answer this question.

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.