Bash scripting with IFS - bash

I need in Bash with IFS=‘,’
./test.sh Mike,Texas Nik,Toronto Lucas,Iowa
Hello Mike
You are from Texas
Hello Nik
You are from Toronto
Hello Lucas
You are from Iowa
#!/bin/bash
IFS=',' read -r -a array <<< "$string"
for index in "${!array[#]}"
do
echo Hello "$index ${array[index]}"
echo You are from "$index ${array[index]}"
done

You don't need to modify IFS (the Internal Field Separator), you need parameter expansion with substring removal, e.g.
#!/bin/bash
for i in "$#"; do
printf "Hello %s\nYou are from %s\n" "${i%,*}" "${i#*,}"
done
Example Use/Output
$ ./test.sh Mike,Texas Nik,Toronto Lucas,Iowa
Hello Mike
You are from Texas
Hello Nik
You are from Toronto
Hello Lucas
You are from Iowa

You can loop over arguments using just for argument - this will populate the variable named argument with the space separated arguments one at a time. Then you can read the comma-separated values. For example:
set -- Mike,Texas Nik,Toronto Lucas,Iowa # For testing purposes
for argument
do
IFS=, read name state <<< "$parameter"
echo "Hello ${name}"
echo "You are from ${state}"
done

Based on what I see, here is my suggestion:
for i in $* ; do
name=$(echo $i | awk -F, '{print $1}' )
wherefrom=$(echo $i | awk -F, '{print $2'})
echo Hello $name, you are from $wherefrom
done

Related

program that prints input in bash

I am new to bash and I struggling with a program. I want to write a program that first asks for user input and afterwards prints the words with an \n(blank line) between them. The last echo contains the amount of characters that is written. Also the output can only contain the words and no digits. E.g:
Input: hallo1 user2 Pete4
Ouput: hallo
user
Pete
13 Characters
This is my code for the time beeing.
echo Typ one or multiple words:
read varname
arr=( "${arr[#]}" "$varname" )
for i in "${arr[#]}"; do
echo "$i"
done
echo ${arr[#]}
# printf '%s\n' "${arr[#]}"
Try this. Works for me. I added in the for the sentence to remove the digits.
And after the for, I first remove the spaces between the names and then I count the total of characters using the # in ${#aux}. I added the parameter -n in the first echo too, just to break the line with the second one.
echo Type one or multiple words:
read varname
arr=( "${arr[#]}" "$varname" )
for i in "${arr[#]//[[:digit:]]/}"; do
echo -n "$i"
done
aux=$(echo "${i}" | sed "s/ //g")
echo " " ${#aux} " Characters"
An approach in plain bash without using an array:
#!/bin/bash
echo 'Type one or multiple words on a line:'
read -r
words_without_digits=${REPLY//[0-9]}
line_without_blanks=${words_without_digits//[[:blank:]]}
printf '%s\n' $words_without_digits
echo "${#line_without_blanks} Characters"
echo Type one or multiple words:
read varname
arr=( "${arr[#]}" "$varname" )
for i in "${arr[#]//[[:digit:]]/}"; do
printf '%s\n' $i
done
aux=$(echo "${i}" | sed "s/ //g")
echo ${#aux} " Characters"

Awk split use array later in bash

If I have this awk command...
echo $line | awk '{split($0,array,"|")}'
...how can I use array later in the bash program? If I try to print out information from the array later it's just empty.
You can't access awk variables outside of awk, but you can do the same using bash arrays directly
$ IFS='|' read -r -a array <<< "a|b|c"; echo ${array[1]}
b
You can use awk array contents outside of awk if you print it:
IFS=$'\n' read -d '' -r -a line < <(echo 'o|p|s' | awk '{split($0,array,"|"); for (i in array) print array[i]}')
declare -p line
# OUTPUT: declare -a line='([0]="o" [1]="p" [2]="s")'
An other solution in bash if I presume that fields haven't got space then only 1 assignment.
ln="apple|lemon|orange|strawberry" # eg
v=(${ln//|/ }) # substitute | with " " and vectorising with ()
# Now we are ready
# checking it:
for((i=0;i<${#v[#]};i++));do echo ${v[$i]}; done
apple
lemon
orange
strawberry
#or:
for i in ${v[#]}; do echo $i; done
apple
lemon
orange
strawberry
If we have some space but no underline "_" we need 3 steps.
ln="api ple|l em on|ora nge|s traw berry"
echo "$ln"
api ple|l em on|ora nge|s traw berry
ln=${ln// /_} # 1st
echo "$ln"
api_ple|l_em__on|ora__nge|s_traw___berry
v=(${ln//|/ }) # 2nd
for i in ${v[#]}; do echo $i; done
api_ple
l_em__on
ora__nge
s_traw___berry
for((i=0;i<${#v[#]};i++));do v[$i]="${v[i]//_/ }"; done # 3rd
for((i=0;i<${#v[#]};i++));do echo "${v[$i]}"; done
api ple
l em on
ora nge
s traw berry

Print bash arguments in reverse order

I have to write a script, which will take all arguments and print them in reverse.
I've made a solution, but find it very bad. Do you have a smarter idea?
#!/bin/sh
> tekst.txt
for i in $*
do
echo $i | cat - tekst.txt > temp && mv temp tekst.txt
done
cat tekst.txt
Could do this
for (( i=$#;i>0;i-- ));do
echo "${!i}"
done
This uses the below
c style for loop
Parameter indirect expansion
(${!i}towards the bottom of the page)
And $# which is the number of arguments to the script
you can use this one liner:
echo $# | tr ' ' '\n' | tac | tr '\n' ' '
bash:
#!/bin/bash
for i in "$#"; do
echo "$i"
done | tac
call this script like:
./reverse 1 2 3 4
it will print:
4
3
2
1
Portably and POSIXly, without arrays and working with spaces and newlines:
Reverse the positional parameters:
flag=''; c=1; for a in "$#"; do set -- "$a" ${flag-"$#"}; unset flag; done
Print them:
printf '<%s>' "$#"; echo
Reversing a simple string, by spaces
Simply:
#!/bin/sh
o=
for i;do
o="$i $o"
done
echo "$o"
will work as
./rev.sh 1 2 3 4
4 3 2 1
Or
./rev.sh world! Hello
Hello world!
If you need to output one line by argument
Just replace echo by printf "%s\n":
#!/bin/sh
o=
for i;do
o="$i $o"
done
printf "%s\n" $o
Reversing an array of strings
If your argument could contain spaces, you could use bash arrays:
#!/bin/bash
declare -a o=()
for i;do
o=("$i" "${o[#]}")
done
printf "%s\n" "${o[#]}"
Sample:
./rev.sh "Hello world" print will this
this
will
print
Hello world
As a function (If you're ok to play with eval.
But eval is evil!!
rev() { eval "set --" $(seq -f '"${%g}"' $# -1 1);printf '%s\n' "$#";}
Then
rev Hello\ world print will this
this
will
print
Hello world

How to assign each line in a text to an array in shell scripting?

I have a text file named "raj.txt" containing following content:
raj
magesh
popey
ravi
How can I assign each word to array element?
a[0]=raj
a[1]=magesh
a[2]=popey
a[3]=ravi
Try bash:
while IFS= read -r line
do
set -- $line
echo "$1"
echo "$2"
done < file
If your shell support array, like bash, zsh, ksh93, try:
$ array=($(<filename))
$ printf '%s\n' "${array[0]}"
raj
$ printf '%s\n' "${array[1]}"
magesh
$ printf '%s\n' "${array[2]}"
popey
$ printf '%s\n' "${array[3]}"
ravi

Splitting a text in Unix

I am writing a simple script that splits a variable that holds some text by using below code:
#!/bin/sh
SAMPLE_TEXT=hello.world.testing
echo $SAMPLE_TEXT
OUT_VALUE=$SAMPLE_TEXT | cut -d'.' -f1
echo output is $OUT_VALUE
I am expecting output as output is hello but when I run this program then I am getting output as output is. Please let me know where I am doing mistake?
To evaluate a command and store it into a variable, use var=$(command).
All together, your code works like this:
SAMPLE_TEXT="hello.world.testing"
echo "$SAMPLE_TEXT"
OUT_VALUE=$(echo "$SAMPLE_TEXT" | cut -d'.' -f1)
# OUT_VALUE=$(cut -d'.' -f1 <<< "$SAMPLE_TEXT") <--- alternatively
echo "output is $OUT_VALUE"
Also, note I am adding quotes all around. It is a good practice that will help you in general.
Other approaches:
$ sed -r 's/([^\.]*).*/\1/g' <<< "$SAMPLE_TEXT"
hello
$ awk -F. '{print $1}' <<< "$SAMPLE_TEXT"
hello
$ echo "${SAMPLE_TEXT%%.*}"
hello
The answer by fedorqui is the correct answer. Just adding another approach...
$ SAMPLE_TEXT=hello.world.testing
$ IFS=. read OUT_VALUE _ <<< "$SAMPLE_TEXT"
$ echo output is $OUT_VALUE
output is hello
Just to expand on #anishane's comment to his own answer:
$ SAMPLE_TEXT="hello world.this is.a test string"
$ IFS=. read -ra words <<< "$SAMPLE_TEXT"
$ printf "%s\n" "${words[#]}"
hello world
this is
a test string
$ for idx in "${!words[#]}"; do printf "%d\t%s\n" $idx "${words[idx]}"; done
0 hello world
1 this is
2 a test string

Resources