Craxxurz
Craxxurz

Reputation: 105

How to split a string in Bash?

I have a variable x which contains a string like "2025-12-13-04-32 Hello StackOverflow programmers".

How can I split it in several variables like this:

d=2015
m=12
dy=13 
h=04
mi=32 
t="Hello StackOverflow programmers"

Upvotes: 3

Views: 218

Answers (4)

mklement0
mklement0

Reputation: 437042

A single read command will do:

input='2025-12-13-04-32 Hello stackoverflow programmers'

IFS='- ' read -r d m dy h mi t <<<"$input"

Note: <<< is a so-called here-string, which allows providing a regular string [variable] via stdin, related to the multi-line here-doc (something starting with, e.g., <<EOF). Here it is the shorter and more efficient alternative to echo "$input" | IFS='- ' read ...

  • IFS='- ' causes read to split the input line into tokens by either a space or a -.
  • Even though that would normally also break the string 'Hello stackoverflow programmers' into 3 tokens, it doesn't here, because read assigns the remainder of the line to the last variable specified, in case there aren't enough variables to match the resulting tokens; thus, variable $t receives 'Hello stackoverflow programmers', as desired.

To print the results, use the following:

Note that ${!name} is an instance of variable indirection - accessing a variable through another variable that contains its name.

names=( d m dy h mi t )
for name in "${names[@]}"; do
  printf '%s=%s\n' "$name" "${!name}"
done

This yields:

d=2025
m=12
dy=13
h=04
mi=32
t=Hello stackoverflow programmers

A note on the choice of approach:

  • read is great for field-based parsing based on a set of literal separator characters (a caveat is that each instance of a non-whitespace separator char. counts).
    • With read -ra, you can even read all tokens into an array, without having to know the number of tokens in advance.
  • For more flexible parsing (based on a known number of tokens), consider use of =~ with regular expressions, as in Jahid's answer.

Upvotes: 10

g000ze
g000ze

Reputation: 290

To automatically assign whitespace separated values to variable names, you could do this:

x="2025-12-13-04-32 Hello stackoverflow programmers"
read -r d m dy h mi <<< "$x"

But since the beginning of the string contains dash signs (-) you first have to replace them with whitespaces:

x="2025-12-13-04-32 Hello stackoverflow programmers"
x="$(echo "$x" | sed 's/-/ /g')"
read -r d m dy h mi <<< "$x"

Still you have to adjust the number of variable names ;-)

I would say this is what you want:

x="2025-12-13-04-32 Hello stackoverflow programmers"                                                                                        
x="$(echo "$x" | tr '-' ' ')"                                                                                                               
read -r d m dy h mi t <<< "$x"                                                                                                          
echo $d
2025
echo $m
12
echo $dy
13
echo $h 
04
echo $mi
32
echo $t
Hello stackoverflow programmers

Upvotes: 1

choroba
choroba

Reputation: 241738

Using parameter substitution and declare:

#!/bin/bash
x="2025-12-13-04-32 Hello stackoverflow programmers"

Shift () {
    declare -g "$1=${copy%%-*}"
    copy=${copy#*-}
}

copy=$x

for var in d m dy h mi ; do
    Shift $var
done

mi=${mi%% *} # Remove the message
t=${copy#* }

for var in d m dy h mi t ; do
    echo $var ${!var}
done

Upvotes: 0

Jahid
Jahid

Reputation: 22428

Using Bash regex:

#!/bin/bash
s='2025-12-13-04-32 Hello stackoverflow programmers'
pat="([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)[[:space:]]*(.*)"
[[ $s =~ $pat ]]
echo "${BASH_REMATCH[1]}"
echo "${BASH_REMATCH[2]}"
echo "${BASH_REMATCH[3]}"
echo "${BASH_REMATCH[4]}"
echo "${BASH_REMATCH[5]}"
echo "${BASH_REMATCH[6]}"

Output:

2025
12
13
04
32
Hello stackoverflow programmers

Upvotes: 5

Related Questions