Reputation: 105
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
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 -
.'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).
read -ra
, you can even read all tokens into an array, without having to know the number of tokens in advance.=~
with regular expressions, as in Jahid's answer.Upvotes: 10
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
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
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