Home > Back-end >  How to iterate string with blank?
How to iterate string with blank?

Time:08-31

I have next code:

line="95:p1=a b c 95:p2=d e 96:p1=a b c 96:p2=d e"

for l in $line; do
    echo $l
done

I got next:

95:p1=a
b
c
95:p2=d
e
96:p1=a
b
c
96:p2=d
e

But in fact a b c is a whole string in my business, so if possible I could get next with some ways?

95:p1=a b c
95:p2=d e
96:p1=a b c
96:p2=d e

CodePudding user response:

You can't do this with regular parameters. If you want a collection of strings that can contain whitespace, use an array.

line=("95:p1=a b c" "95:p2=d e" "96:p1=a b c" "96:p2=d e")

for l in "${line[@]}"; do
    echo "$l"
done

Otherwise, you'll need some way of distinguishing between "literal" spaces and "delimiter" spaces. (Maybe the latter is followed by <num>:, but that logic is not trivial to implement using bash regular expressions. You would probably be better off using a more capable language instead of trying to do this in bash.)

CodePudding user response:

1st solution: With your shown samples and attempts please try following awk code. Written and tested with GNU awk.

Here is the Online demo for used regex.

echo "$line"
95:p1=a b c 95:p2=d e 96:p1=a b c 96:p2=d e

awk -v RS='[0-9]{2}:p[0-9]=[a-zA-Z] [a-zA-Z]( [a-zA-Z]|$)*' 'RT{print RT}' <<<"$line"

Output with shown samples will be as follows:

95:p1=a b c
95:p2=d e
96:p1=a b c
96:p2=d e


2nd solution: With any POSIX awk please try following awk code:

awk '
{
  while(match($0,/[0-9]{2}:p[0-9]=[a-zA-Z] [a-zA-Z]( [a-zA-Z]|$)*/)){
    print substr($0,RSTART,RLENGTH)
    $0=substr($0,RSTART RLENGTH)
  }
}
' <<<"$line"

CodePudding user response:

With bash

read -ra f <<<"$line"    # split the string into words
n=${#f[@]}
i=0
lines=()
while ((i < n)); do
    l=${f[i  ]}
    until ((i == n)) || [[ ${f[i]} =~ ^[0-9] : ]]; do
        l =" ${f[i  ]}"
    done
    lines =( "$l" )
done
declare -p lines

outputs

declare -a lines=([0]="95:p1=a b c" [1]="95:p2=d e" [2]="96:p1=a b c" [3]="96:p2=d e")

Now you can do

for l in "${lines[@]}"; do
    do_something_with "$l"
done

Or , and capture the lines with bash builtin mapfile

mapfile -t lines < <(sed -E 's/ ([0-9] :)/\n\1/g' <<< "$line")

CodePudding user response:

echo "${line}" | 

mawk 'BEGIN { FS=RS="^$"(ORS="") } gsub(" [^ :] :","\1&")   gsub("\1.","\n")^_'
95:p1=a b c
95:p2=d e
96:p1=a b c
96:p2=d e
  • Related