idobr
idobr

Reputation: 1647

Bash split string

I have the following data in array:

MY_ARR[0]="./path/path2/name.exe 'word1 word2' 'name1,name2'" 
MY_ARR[1]="./path/path2/name.exe 'word1 word2' 'name3,name4,name5'"
MY_ARR[2]=".name.exe 'word1 word2'"
MY_ARR[3]="name.exe"
MY_ARR[4]="./path/path2/name.exe 'word1 word2' 'name1'"
MY_ARR[5]="./path/path2/name.exe 'word1 word2' 'name.exe, name4.exe, name5.exe'"

I want to divide it into two variables: $file and $parameter.

Example:

file="./path/path2/name.exe"
parameter="'word1 word2' 'name1,name2'"

I can do it with awk:

parameter=$(echo "${MY_ARR[1]}" | awk -F\' '{print $2 $4}')
file=$(echo "${MY_ARR[1]}" | awk -F\' '{print $1}')

This needs to remove trailing spaces and looks to complicated.

Is there a better way to do it?

Upvotes: 8

Views: 21892

Answers (4)

Reinstate Monica Please
Reinstate Monica Please

Reputation: 11633

Unless I'm missing something, simplest and most portable way would be to just use two variations of expansion for this.

file="${MY_ARR[0]%%' '*}"
parameter="${MY_ARR[0]#*' '}"

Explanation

  • "${MY_ARR[0]%%' '*}" - This removes the first space and anything after it, and returns remaining part
  • "${MY_ARR[0]#*' '}" - This removes everything up to the first space, and returns the remaining part

For a more detailed explanation, see the Parameter Expansion section of the bash man page

Upvotes: 1

fedorqui
fedorqui

Reputation: 290515

It looks like the separator between the fields is an space. Hence, you can use cut to split them:

file=$(echo "${MY_ARR[1]}" | cut -d' ' -f1)
parameter=$(echo "${MY_ARR[1]}" | cut -d' ' -f2-)
  • -f1 means the first parameter.
  • -f2- means everything from the second parameter.

Upvotes: 15

Zhoul
Zhoul

Reputation: 21

Given this array:

    MY_ARR[0]="./path/path2/name.exe 'word1 word2' 'name1,name2'"
    MY_ARR[1]="./path/path2/name.exe 'word1 word2' 'name3,name4,name5'"
    MY_ARR[2]=".name.exe             'word1 word2'"
    MY_ARR[3]="name.exe"
    MY_ARR[4]="./path/path2/name.exe 'word1 word2' 'name1'"
    MY_ARR[5]="./path/path2/name.exe 'word1 word2' 'name.exe, name4.exe, name5.exe'"

Lets make 2 new arrays MY_FILES and MY_PARAMETERS

    for  MY_ARR_INDEX in  ${!MY_ARR[*]}  ;  do

         ######
         # Set the current file in new array.

              MY_FILES[ ${MY_ARR_INDEX} ]=${MY_ARR[ ${MY_ARR_INDEX} ]// *}

         ######
         # Set the current parameters in new array

         MY_PARAMETERS[ ${MY_ARR_INDEX} ]=${MY_ARR[ ${MY_ARR_INDEX} ]#* }

         ######
         # Show the user whats happening
         # (from here until done is just printing info.)

         printf "MY_FILES[ ${MY_ARR_INDEX} ]=\"%s\"  ;  MY_PARAMETERS[ ${MY_ARR_INDEX} ]=\"%s\"\n" \
         \
          "${MY_ARR[ ${MY_ARR_INDEX} ]// *}"  "${MY_ARR[ ${MY_ARR_INDEX} ]#* }"

    done


    MY_FILES[ 0 ]="./path/path2/name.exe"  ;  MY_PARAMETERS[ 0 ]="'word1 word2' 'name1,name2'"
    MY_FILES[ 1 ]="./path/path2/name.exe"  ;  MY_PARAMETERS[ 1 ]="'word1 word2' 'name3,name4,name5'"
    MY_FILES[ 2 ]=".name.exe"  ;  MY_PARAMETERS[ 2 ]="            'word1 word2'"
    MY_FILES[ 3 ]="name.exe"  ;  MY_PARAMETERS[ 3 ]="name.exe"
    MY_FILES[ 4 ]="./path/path2/name.exe"  ;  MY_PARAMETERS[ 4 ]="'word1 word2' 'name1'"
    MY_FILES[ 5 ]="./path/path2/name.exe"  ;  MY_PARAMETERS[ 5 ]="'word1 word2' 'name.exe, name4.exe, name5.exe'"

How to access each file:

    for  MY_ARR_INDEX in  ${!MY_FILES[*]}  ;  do

         CUR_FILE=${MY_FILES[ ${MY_ARR_INDEX} ] }

         echo "# Do something with this file: ${CUR_FILE}"

    done

Output:

    Do something with this file: ./path/path2/name.exe
    Do something with this file: ./path/path2/name.exe
    Do something with this file: .name.exe
    Do something with this file: name.exe
    Do something with this file: ./path/path2/name.exe
    Do something with this file: ./path/path2/name.exe

How to access each parameter :

    for  MY_ARR_INDEX in  ${!MY_PARAMETERS[*]}  ;  do

         CUR_FILE=${MY_FILES[ ${MY_ARR_INDEX} ]}

         echo "# Do something with this parameter: ${CUR_FILE}"

    done

Output:

    Do something with this parameter: ./path/path2/name.exe
    Do something with this parameter: ./path/path2/name.exe
    Do something with this parameter: .name.exe
    Do something with this parameter: name.exe
    Do something with this parameter: ./path/path2/name.exe
    Do something with this parameter: ./path/path2/name.exe

Since ${!MY_FILES[ [*]} results in the index NUMBERS of array MY_FILES you can also use the same index numbers to access the other arrays.In this way, you may access multiple columns of data in the same loop. Like so:

    ################
    #
    # Print each file and matching parameter(s)
    #
    ################

    # Set a printf format string so we can print all things nicely.

    MY_PRINTF_FORMAT="#  %25s  %s\n"

    ################
    #
    # Print the column headings and use index numbers
    #
    #        to print adjacent array elements.
    #
    ################
    (

            printf   "${MY_PRINTF_FORMAT}"  "FILE" "PARAMETERS"    "----" "----------"

        for  MY_ARR_INDEX in  ${!MY_FILES[*]}  ;  do

             printf  "${MY_PRINTF_FORMAT}"  "${MY_FILES[ ${MY_ARR_INDEX} ]}"  "${MY_PARAMETERS[ ${MY_ARR_INDEX} ]}"

        done
    )

Output :

                           FILE  PARAMETERS
                           ----  ----------
          ./path/path2/name.exe  'word1 word2' 'name1,name2'
          ./path/path2/name.exe  'word1 word2' 'name3,name4,name5'
                      .name.exe              'word1 word2'
                       name.exe  name.exe
          ./path/path2/name.exe  'word1 word2' 'name1'
          ./path/path2/name.exe  'word1 word2' 'name.exe, name4.exe, name5.exe'

Upvotes: 2

Thor
Thor

Reputation: 47239

You can use read:

$ read file parameter <<< ${MY_ARR[1]}
$ echo "$file"
./path/path2/name.exe
$ echo "$parameter"
'word1 word2' 'name3,name4,name5'

Upvotes: 5

Related Questions