bash: read string into array bash with spaces preserved [duplicate] - bash

This question already has answers here:
Bash: Split string into character array
(20 answers)
Closed 9 years ago.
I have string "hi how are you"
I want to put this string into an array as shown below. But i want to preserve spaces. Any ideas on how to do that?
a[0] a[1] a[2] 3 4 5 6 .... should have
h i <space> h o w <space> .... and so on.

One way, sure there will be better solutions but this seems to work for me:
unset arr; IFS=; for c in $(sed 's/./&\n/g' <<<"hi how are you"); do arr+=("$c"); done; echo "${arr[#]}"
It yields:
h
i
h
o
w
a
r
e
y
o
u

eval a=( $(echo "hi how are you" | sed "s/\(.\)/'\1' /g") )
It's really ugly, maybe somebody can come up with something without eval...

Probably not fast, but avoids the need for sed:
z=()
while read -n 1 x; do
z+=( "$x" )
done <<<"hi how are you"

Related

Split String by Double Back Slashes in Bash

I am trying to split the string by double back slashes in bash and somehow it's not working.
My string is as follow:
abc\\xyz
My Code:
my_str='abc\\xyz'
IFS='\\' read -r -a arr <<< "$my_str"
echo "${#arr[#]}"
I am expecting that the output would be '2' as the length of the array would be 2.
However, I get 3 as a result and when I try to print the array values, I only get 'abc', and the second index remains empty. It seems like something is wrong with my code but I am unable to identify it.
Can anyone please help to resolve the issue?
If there are no spaces in your string you could use bash pattern substitutions to replace pairs of backslashes by a space and assign the result to an indexed array:
$ my_str='abc\\xyz\uvw\\rst\\\012\\\\345'
$ declare -a arr=( ${my_str//\\\\/ } )
$ echo "${#arr[#]}"
5
$ printf '%s\n' "${arr[#]}"
abc
xyz\uvw
rst
\012
345
Perhaps you could try to replace the backslashes on the string fist as showcased in this previous question. However, this would be inefficient for very large strings.
A slightly different take -
$: my_str='abc\\123\\ghi\\\012\\jkl\\foo bar\\\\xyz'
$: IFS='|' read -r -a arr <<< "${my_str//\\\\/\|}"
$: printf "[%s]\n" "${arr[#]}"
[abc]
[123]
[ghi]
[\012]
[jkl]
[foo bar]
[]
[xyz]

bash loop through all chars in string [duplicate]

This question already has answers here:
How to perform a for loop on each character in a string in Bash?
(16 answers)
Closed 7 years ago.
How should I loop through all chars in a string.
My pseudocode
stringVar="abcde"
for var in stringvar
{
do some things with var
}
result i need
a
b
c
d
I want to loop all the vars but i can only get it to work with a whitespace splitted var like
stringVar="a b c"
for var in stringVar; do
echo $var
done;
result
a
b
c
but i cant do it for a string that isnt split with whitespaces.
The question is flagged as duplicate but not one of the answers (with upvotes) is available in the linked questions..
You can use read for that:
string="abcde"
while read -n 1 char ; do
echo "$char"
done <<< "$string"
Using -n 1 read will read one character at a time. However, the input redirection <<< adds a newline to the end of $string.
stringVar="abcde"
for ((i=1;i<=${#stringVar};i++)); do
echo ${stringVar:$i-1:1}
done
Output:
a
b
c
d
e

How can I get the first string from a Bash list? [duplicate]

This question already has answers here:
How can I retrieve the first word of the output of a command in Bash?
(13 answers)
Closed 1 year ago.
I do have a Bash list (space separated string) and I just want to extract the first string from it.
Example:
VAR="aaa bbb ccc" -> I need "aaa"
VAR="xxx" -> I need "xxx"
Is there another trick than using a for with break?
Use cut:
echo $VAR | cut --delimiter " " --fields 1 # Number after fields is the
# index of pattern you are retrieving
Try this format:
echo "${VAR%% *}"
Another way is:
read FIRST __ <<< "$VAR"
echo "$FIRST"
If you want arrays, use arrays. ;)
VAR=(aaa bbb ccc)
echo ${VAR[0]} # -> aaa
echo ${VAR[1]} # -> bbb
I'm not sure how standard this is, but this works in Bash 4.1.11
NewVAR=($VAR)
echo $NewVAR
At this moment the only solution that worked, on both Linux and OS X was:
IP="1 2 3"
for IP in $IP:
do
break
done

BASH split variable in characters and print out space in for loop

I am trying to create a fancy welcome message to be displayed when the terminal is opened. I have done it in Java with this code:
public void slowPrint() {
String message = "Welcome, " + System.getProperty("user.name");
try {
for(int i = 0; i < message.length(); i++) {
System.out.print(message.charAt(i));
Thread.sleep(50);
}
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}
Now, I am fairly new to bash but I've managed to make this code:
for i in W e l c o m e , $USER; do
echo -ne $i
sleep 0.05
done
echo !
There are two problems with this code:
I have no idea how to print a plain space after the comma, the output is just Welcome,simon! How can I make it output a space instead?
It, of course, prints $USER as a whole word. I would want it to be character by character, how can I do this?
You could use a standard for loop to achieve the same effect:
MESSAGE="Welcome, $USER"
for (( i=0; i<${#MESSAGE}; i++ )); do
echo -ne "${MESSAGE:$i:1}"
sleep 0.05
done
echo !
The ${MESSAGE:$i:1} syntax takes a substring of 1 from position i in the string. Enclosing that part in quotes ensures that things like spaces and tabs are also printed.
You can specify the space easily enough; enclose it in quotes:
for i in W e l c o m e , ' ' ...
Splitting $USER into separate characters can be done many ways. The way I'd do it is old-fashioned but reliable:
for i in W e l c o m e , ' ' $(sed 's/./& /g' <<< "$USER")
Note that the <<< operation saves a process and a pipe; it redirects standard input of sed so it reads the given string as a line of input.
Or, if you think the user name might contain any spaces or other special characters:
for i in W e l c o m e , ' ' $(sed "s/./'&' /g" <<< "$USER")
(This isn't bullet proof; the value USER="Tam O'Shanter" will cause some grief, and the simple fix for that runs into trouble with USER='Will "O'\''Wisp" Light' instead. ...mutter, mutter, arcane incantations, ...
for i in W e l c o m e , ' ' $(sed "s/./'&' /g; s/'''/\\\\'/g" <<< "$USER")
except that echoes the name with single quotes around everything; grumble, grumble, ... I think I've just worked out why I wouldn't ever both to do this, ... spaces get in the way too ... I'd use the simple first version and tell people not to use blanks or special characters in the value of $USER.)
There might be are ways to do it without invoking a separate process such as sed; see the answer by heuristicus. So, do it that way. But note that it is firmly tied to bash in a way that this answer isn't wholly tied to bash — you can easily replace the <<< notation (which is bash-only) with echo "$USER" | ... instead.
Completely POSIXly portable, i.e. without those pesky bashisms, and no fork to sed:
#!/bin/sh
m="Welcome, $USER!"
while test ${#m} -gt 0; do
r=${m#?}
printf '%s ' "${m%%$r}"
m=$r
sleep 0.05
done
printf '\n'
Note that sleeping for fractions of a second is non-portable.

Looping through alphabets in Bash

I want to mv all the files starting with 'x' to directory 'x'; something like:
mv path1/x*.ext path2/x
and do it for all alphabet letters a, ..., z
How can I write a bash script which makes 'x' loops through the alphabet?
for x in {a..z}
do
echo "$x"
mkdir -p path2/${x}
mv path1/${x}*.ext path2/${x}
done
This should get you started:
for letter in {a..z} ; do
echo $letter
done
here's how to generate the Spanish alphabet using nested brace expansion
for l in {{a..n},ñ,{o..z}}; do echo $l ; done | nl
1 a
...
14 n
15 ñ
16 o
...
27 z
Or simply
echo -e {{a..n},ñ,{o..z}}"\n" | nl
If you want to generate the obsolete 29 characters Spanish alphabet
echo -e {{a..c},ch,{d..l},ll,{m,n},ñ,{o..z}}"\n" | nl
Similar could be done for French alphabet or German alphabet.
Using rename:
mkdir -p path2/{a..z}
rename 's|path1/([a-z])(.*)|path2/$1/$1$2' path1/{a..z}*
If you want to strip-off the leading [a-z] character from filename, the updated perlexpr would be:
rename 's|path1/([a-z])(.*)|path2/$1/$2' path1/{a..z}*
With uppercase as well
for letter in {{a..z},{A..Z}}; do
echo $letter
done
This question and the answers helped me with my problem, partially.
I needed to loupe over a part of the alphabet in bash.
Although the expansion is strictly textual
I found a solution: and made it even more simple:
START=A
STOP=D
for letter in $(eval echo {$START..$STOP}); do
echo $letter
done
Which results in:
A
B
C
D
Hope its helpful for someone looking for the same problem i had to solve,
and ends up here as well
I hope this can help.
for i in {a..z}
for i in {A..Z}
for i in {{a..z},{A..Z}}
use loop according to need.

Resources