how to insert new line in bash shell for variable? - bash

I have two variables var1 and var2. The contents of each variables come from bash shell grep command.
echo $var1 prints
123 465 326 8080
echo $var2 prints
sila kiran hinal juku
Now I want to print the above into following formats in Linux bash shell
123 sila
465 kiran
326 hinal
8080 juku
So how can I print this way in bash shell??

What about?
$ paste -d" " <(echo $var1 | xargs -n1) <(echo $var2 | xargs -n1)
We can even skip the echo:
$ paste -d" " <(xargs -n1 <<< $var1) <(xargs -n1 <<< $var2)

Without a loop:
$ var1="123 465 326 8080"
$ var2="sila kiran hinal juku"
$ var1=($var1); var2=($var2)
$ saveIFS=IFS
$ IFS=$'\n'
$ paste <(echo "${a[*]}") <(echo "${b[*]}"
$ IFS=$saveIFS
With a loop (assumes that the two strings have the same number of words):
$ var1="123 465 326 8080"
$ var2="sila kiran hinal juku"
$ var2=($var2)
$ for s in $var1; do echo $s ${vars[i++]}; done

Using file descriptors and a while-loop:
var1="123 465 326 8080"
var2="sila kiran hinal juku"
IFS=" " exec 7< <(printf "%s\n" $var1) 8< <(printf "%s\n" $var2)
while read -u7 f1 && read -u8 f2; do
echo "$f1 $f2"
done

I'd store them into arrays $var1[] and $var2[] instead of a some long string and then iterate through the arrays with a loop to output it the way you want.
If you don't want ot use arrays, you could use awk and the iterator from a loop to print out the names one at a time.

join <(echo $var1 | sed -r 's/ +/\n/g' | cat -n) <(echo $var2 | sed -r 's/ +/\n/g' | cat -n) -o "1.2,2.2"

Related

echo strings with envrionment variables from lines pulled from a file in bash

I have a file like so:
- ${VAR1}/blah/blah:/blah1
- ${VAR2}/blah/blah:/blah2
- $VAR3:/blah3
I ultimately need to create those three folders.
I am using sed to extract the folder part:
$ cat test.txt | grep -E '^ +- \$.*?:.*?$' | sed 's/.*- \(\$.*\):.*/\1/g'
${VAR1}/blah/blah
${VAR2}/blah/blah
$VAR3
I need to create those folders but I need those shell variables to expand. Right now they don't:
$ cat test.txt | grep -E '^ +- \$.*?:.*?$' | sed 's/.*- \(\$.*\):.*/\1/g' | while read line; do echo "$line"; done
${VAR1}/blah/blah
${VAR2}/blah/blah
$VAR3
Is there a way to get the expanded strings so I can run mkdir instead of echo to make the folders?
You may use this bash script with envsubst:
#!/usr/bin/env bash
export VAR1 VAR2 VAR3
while IFS=' -:' read -r _ d _; do
mkdir -p "$d"
done < <(envsubst < test.txt)
Alternatively use this envsubst + awk + xargs solution:
envsubst < text.txt |
awk -F '[-:[:blank:]]+' -v ORS='\0' '{print $2}' |
xargs -0 mkdir -p
First of all those variables should be exported to be accessible from your script. Then you could just use the cut and tr commands combination to extract dir name in a loop like the following:
#!/bin/bash -eu
while read -r LINE; do
echo "$LINE" | cut -d ':' -f 1 | tr -d ' ' | tr -d '-'
done < test.txt

Read file sed the line before send the params into array

i try to remove some string of my result before to send them on my array . i tried different stuff but i didn't found it :(
actually in my $LOGFILE i've something like that :
STATUS TO_CHAR(TO_TIMESTAM
--------------- -------------------
AVAILABLE 2017.10.18 18:00:30
AVAILABLE 2017.10.24 18:00:26
And i try to have only the date 2017.10.18 18:00:30
function read_file {
while read line;do
arr[$i]="$line"
i=$((i+1))
# $line | sed s/"-"//g | sed s/"STATUS"//g | sed s/'TO_CHAR(TO_TIMESTAM'//g | sed s/"AVAILABLE"//g | sed '/^ *$/d'
done< $LOGFILE
printf '%s\n' "${arr[#]}"
}
Would grep be acceptable?
grep -o '[0-9].*' $LOGFILE
Output:
2017.10.18 18:00:30
2017.10.24 18:00:26
Use mapfile to capture the output in an array.
$ mapfile -t arr < <(grep -o '[0-9].*' $LOGFILE)
$ echo ${arr[0]}
2017.10.18 18:00:30
$ echo ${arr[1]}
2017.10.24 18:00:26
Many thanks to this post.

Remove all chars that are not a digit from a string

I'm trying to make a small function that removes all the chars that are not digits.
123a45a ---> will become ---> 12345
I've came up with :
temp=$word | grep -o [[:digit:]]
echo $temp
But instead of 12345 I get 1 2 3 4 5. How to I get rid of the spaces?
Pure bash:
word=123a45a
number=${word//[^0-9]}
Here's a pure bash solution
var='123a45a'
echo ${var//[^0-9]/}
12345
is this what you are looking for?
kent$ echo "123a45a"|sed 's/[^0-9]//g'
12345
grep & tr
echo "123a45a"|grep -o '[0-9]'|tr -d '\n'
12345
I would recommend using sed or perl instead:
temp="$(sed -e 's/[^0-9]//g' <<< "$word")"
temp="$(perl -pe 's/\D//g' <<< "$word")"
Edited to add: If you really need to use grep, then this is the only way I can think of:
temp="$( grep -o '[0-9]' <<< "$word" \
| while IFS= read -r ; do echo -n "$REPLY" ; done
)"
. . . but there's probably a better way. (It uses grep -o, like your solution, then runs over the lines that it outputs and re-outputs them without line-breaks.)
Edited again to add: Now that you've mentioned that you use can use tr instead, this is much easier:
temp="$(tr -cd 0-9 <<< "$word")"
What about using sed?
$ echo "123a45a" | sed -r 's/[^0-9]//g'
12345
As I read you are just allowed to use grep and tr, this can make the trick:
$ echo "123a45a" | grep -o [[:digit:]] | tr -d '\n'
12345
In your case,
temp=$(echo $word | grep -o [[:digit:]] | tr -d '\n')
tr will also work:
echo "123a45a" | tr -cd '[:digit:]'
# output: 12345
Grep returns the result on different lines:
$ echo -e "$temp"
1
2
3
4
5
So you cannot remove those spaces during the filtering, but you can afterwards, since $temp can transform itself like this:
temp=`echo $temp | tr -d ' '`
$ echo "$temp"
12345

Setting variables in shell script by running commands

>cat /tmp/list1
john
jack
>cat /tmp/list2
smith
taylor
It is guaranteed that list1 and list2 will have equal number of lines.
f(){
i=1
while read line
do
var1 = `sed -n '$ip' /tmp/list1`
var2 = `sed -n '$ip' /tmp/list2`
echo $i,$var1,$var2
i=`expr $i+1`
echo $i,$var1,$var2
done < $INFILE
}
So output of f() should be:
1,john,smith
2,jack,taylor
But getting
1,p,p
1+1,p,p
If i replace following:
var1 = `sed -n '$ip' /tmp/list1`
var2 = `sed -n '$ip' /tmp/list2`
with this:
var1=`head -$i /tmp/vip_list|tail -1`
var2=`head -$i /tmp/lb_list|tail -1`
Then output:
1,john,smith
1,john,smith
If you can use paste and awk command, you can achieve the same with a one-liner:
paste -d, /tmp/list1 /tmp/list2 | awk '{print NR "," $0}'
Replace the while script with this line :)
the $ip is the problem there making ip the name of the variable, you should use ${i}p instead letting the shell know that the variable is i not ip, your code should look like
var1=`sed -n "${i}p" /tmp/list1`
var2=`sed -n "${i}p" /tmp/list2`

Redirect output to a bash array

I have a file containing the string
ipAddress=10.78.90.137;10.78.90.149
I'd like to place these two IP addresses in a bash array. To achieve that I tried the following:
n=$(grep -i ipaddress /opt/ipfile | cut -d'=' -f2 | tr ';' ' ')
This results in extracting the values alright but for some reason the size of the array is returned as 1 and I notice that both the values are identified as the first element in the array. That is
echo ${n[0]}
returns
10.78.90.137 10.78.90.149
How do I fix this?
Thanks for the help!
do you really need an array
bash
$ ipAddress="10.78.90.137;10.78.90.149"
$ IFS=";"
$ set -- $ipAddress
$ echo $1
10.78.90.137
$ echo $2
10.78.90.149
$ unset IFS
$ echo $# #this is "array"
if you want to put into array
$ a=( $# )
$ echo ${a[0]}
10.78.90.137
$ echo ${a[1]}
10.78.90.149
#OP, regarding your method: set your IFS to a space
$ IFS=" "
$ n=( $(grep -i ipaddress file | cut -d'=' -f2 | tr ';' ' ' | sed 's/"//g' ) )
$ echo ${n[1]}
10.78.90.149
$ echo ${n[0]}
10.78.90.137
$ unset IFS
Also, there is no need to use so many tools. you can just use awk, or simply the bash shell
#!/bin/bash
declare -a arr
while IFS="=" read -r caption addresses
do
case "$caption" in
ipAddress*)
addresses=${addresses//[\"]/}
arr=( ${arr[#]} ${addresses//;/ } )
esac
done < "file"
echo ${arr[#]}
output
$ more file
foo
bar
ipAddress="10.78.91.138;10.78.90.150;10.77.1.101"
foo1
ipAddress="10.78.90.137;10.78.90.149"
bar1
$./shell.sh
10.78.91.138 10.78.90.150 10.77.1.101 10.78.90.137 10.78.90.149
gawk
$ n=( $(gawk -F"=" '/ipAddress/{gsub(/\"/,"",$2);gsub(/;/," ",$2) ;printf $2" "}' file) )
$ echo ${n[#]}
10.78.91.138 10.78.90.150 10.77.1.101 10.78.90.137 10.78.90.149
This one works:
n=(`grep -i ipaddress filename | cut -d"=" -f2 | tr ';' ' '`)
EDIT: (improved, nestable version as per Dennis)
n=($(grep -i ipaddress filename | cut -d"=" -f2 | tr ';' ' '))
A variation on a theme:
$ line=$(grep -i ipaddress /opt/ipfile)
$ saveIFS="$IFS" # always save it and put it back to be safe
$ IFS="=;"
$ n=($line)
$ IFS="$saveIFS"
$ echo ${n[0]}
ipAddress
$ echo ${n[1]}
10.78.90.137
$ echo ${n[2]}
10.78.90.149
If the file has no other contents, you may not need the grep and you could read in the whole file.
$ saveIFS="$IFS"
$ IFS="=;"
$ n=$(</opt/ipfile)
$ IFS="$saveIFS"
A Perl solution:
n=($(perl -ne 's/ipAddress=(.*);/$1 / && print' filename))
which tests for and removes the unwanted characters in one operation.
You can do this by using IFS in bash.
First read the first line from file.
Seoncd convert that to an array with = as delimeter.
Third convert the value to an array with ; as delimeter.
Thats it !!!
#!/bin/bash
IFS='\n' read -r lstr < "a.txt"
IFS='=' read -r -a lstr_arr <<< $lstr
IFS=';' read -r -a ip_arr <<< ${lstr_arr[1]}
echo ${ip_arr[0]}
echo ${ip_arr[1]}

Resources