Split string into an array in Bash

后端 未结 22 2587
故里飘歌
故里飘歌 2020-11-22 04:24

In a Bash script I would like to split a line into pieces and store them in an array.

The line:

Paris, France, Europe

I would like

22条回答
  •  迷失自我
    2020-11-22 04:49

    Here's my hack!

    Splitting strings by strings is a pretty boring thing to do using bash. What happens is that we have limited approaches that only work in a few cases (split by ";", "/", "." and so on) or we have a variety of side effects in the outputs.

    The approach below has required a number of maneuvers, but I believe it will work for most of our needs!

    #!/bin/bash
    
    # --------------------------------------
    # SPLIT FUNCTION
    # ----------------
    
    F_SPLIT_R=()
    f_split() {
        : 'It does a "split" into a given string and returns an array.
    
        Args:
            TARGET_P (str): Target string to "split".
            DELIMITER_P (Optional[str]): Delimiter used to "split". If not 
        informed the split will be done by spaces.
    
        Returns:
            F_SPLIT_R (array): Array with the provided string separated by the 
        informed delimiter.
        '
    
        F_SPLIT_R=()
        TARGET_P=$1
        DELIMITER_P=$2
        if [ -z "$DELIMITER_P" ] ; then
            DELIMITER_P=" "
        fi
    
        REMOVE_N=1
        if [ "$DELIMITER_P" == "\n" ] ; then
            REMOVE_N=0
        fi
    
        # NOTE: This was the only parameter that has been a problem so far! 
        # By Questor
        # [Ref.: https://unix.stackexchange.com/a/390732/61742]
        if [ "$DELIMITER_P" == "./" ] ; then
            DELIMITER_P="[.]/"
        fi
    
        if [ ${REMOVE_N} -eq 1 ] ; then
    
            # NOTE: Due to bash limitations we have some problems getting the 
            # output of a split by awk inside an array and so we need to use 
            # "line break" (\n) to succeed. Seen this, we remove the line breaks 
            # momentarily afterwards we reintegrate them. The problem is that if 
            # there is a line break in the "string" informed, this line break will 
            # be lost, that is, it is erroneously removed in the output! 
            # By Questor
            TARGET_P=$(awk 'BEGIN {RS="dn"} {gsub("\n", "3F2C417D448C46918289218B7337FCAF"); printf $0}' <<< "${TARGET_P}")
    
        fi
    
        # NOTE: The replace of "\n" by "3F2C417D448C46918289218B7337FCAF" results 
        # in more occurrences of "3F2C417D448C46918289218B7337FCAF" than the 
        # amount of "\n" that there was originally in the string (one more 
        # occurrence at the end of the string)! We can not explain the reason for 
        # this side effect. The line below corrects this problem! By Questor
        TARGET_P=${TARGET_P%????????????????????????????????}
    
        SPLIT_NOW=$(awk -F"$DELIMITER_P" '{for(i=1; i<=NF; i++){printf "%s\n", $i}}' <<< "${TARGET_P}")
    
        while IFS= read -r LINE_NOW ; do
            if [ ${REMOVE_N} -eq 1 ] ; then
    
                # NOTE: We use "'" to prevent blank lines with no other characters 
                # in the sequence being erroneously removed! We do not know the 
                # reason for this side effect! By Questor
                LN_NOW_WITH_N=$(awk 'BEGIN {RS="dn"} {gsub("3F2C417D448C46918289218B7337FCAF", "\n"); printf $0}' <<< "'${LINE_NOW}'")
    
                # NOTE: We use the commands below to revert the intervention made 
                # immediately above! By Questor
                LN_NOW_WITH_N=${LN_NOW_WITH_N%?}
                LN_NOW_WITH_N=${LN_NOW_WITH_N#?}
    
                F_SPLIT_R+=("$LN_NOW_WITH_N")
            else
                F_SPLIT_R+=("$LINE_NOW")
            fi
        done <<< "$SPLIT_NOW"
    }
    
    # --------------------------------------
    # HOW TO USE
    # ----------------
    
    STRING_TO_SPLIT="
     * How do I list all databases and tables using psql?
    
    \"
    sudo -u postgres /usr/pgsql-9.4/bin/psql -c \"\l\"
    sudo -u postgres /usr/pgsql-9.4/bin/psql  -c \"\dt\"
    \"
    
    \"
    \list or \l: list all databases
    \dt: list all tables in the current database
    \"
    
    [Ref.: https://dba.stackexchange.com/questions/1285/how-do-i-list-all-databases-and-tables-using-psql]
    
    
    "
    
    f_split "$STRING_TO_SPLIT" "bin/psql -c"
    
    # --------------------------------------
    # OUTPUT AND TEST
    # ----------------
    
    ARR_LENGTH=${#F_SPLIT_R[*]}
    for (( i=0; i<=$(( $ARR_LENGTH -1 )); i++ )) ; do
        echo " > -----------------------------------------"
        echo "${F_SPLIT_R[$i]}"
        echo " < -----------------------------------------"
    done
    
    if [ "$STRING_TO_SPLIT" == "${F_SPLIT_R[0]}bin/psql -c${F_SPLIT_R[1]}" ] ; then
        echo " > -----------------------------------------"
        echo "The strings are the same!"
        echo " < -----------------------------------------"
    fi
    

提交回复
热议问题