count specific word in line in bash - bash

i have variable such as "1,2,3,4"
i want to count of commas in this text in bash
any idea ?
thanks for help

This will do what you want:
echo "1,2,3" | tr -cd ',' | wc -c

Off the top of my head using pure bash:
var="1,2,3,4"
temp=${var//[^,]/}
echo ${#temp}

Isolate commas per line, count lines:
echo "$VAR"|grep -o ,|wc -l

very simply with awk
$ echo 1,2,3,4 | awk -F"," '{print NF-1}'
3
with just the shell
$ s="1,2,3,4"
$ IFS=","
$ set -- $s
$ echo $(($#-1))
3

A purely bash solution with no external programs:
$ X=1,2,3,4
$ count=$(( $(IFS=,; set -- $X; echo $#) - 1 ))
$ echo $count
3
$
Note: This destroys your positional parameters.

Another pure Bash solution:
var="bbb,1,2,3,4,a,b,qwerty,,,"
saveIFS="$IFS"
IFS=','
var=($var)x
IFS="$saveIFS"
echo $((${#var[#]} - 1))
will output "10" with the string shown.

echo '1,2,3' | grep -o ',' | wc -l

Related

Get only numbers in output

I need to get only numbers from this:
release/M_0.1.0
thus, need to extract with bash to have in output this:
0.1.0.
I have tried this but cannot finish it:
echo "release/M_0.1.0" | awk -F'/' '{print $2}'
And what about if given such string? relea234se/sdf23_4Mm0.1.0.8. How to get only 0.1.0.8? Please pay attention that this can be random digits such as 0.2 or 1.9.1.
Please check if this grep command works
echo "release/M_0.1.0" | egrep -o '[0-9.]+'
You could also use general parameter expansion parsing to literally remove characters up through the last that isn't digits or dots.
$: ver() { echo "${1//*[^.0-9]/}"; }
$: ver release/M_0.1.0
0.1.0
$: ver relea234se/sdf23_4Mm0.1.0.8
0.1.0.8
With sed you can do:
echo "release/M_0.1.0" | sed 's#.*_##'
Output:
0.1.0
Considering that your Input_file will be same as shown samples.
echo "$var" | awk -F'_' '{print $2}'
OR could use sub:
echo "$var" | awk '{sub(/.*_/,"")} 1'
With simple bash you could use:
echo "${var#*_}"
echo release/M_0.1.0 | awk -F\_ '{print $2}'
0.1.0
Take your pick:
$ var='relea234se/sdf23_4Mm0.1.0.8'
$ [[ $var =~ .*[^0-9.](.*) ]] && echo "${BASH_REMATCH[1]}"
0.1.0.8
$ echo "$var" | sed 's/.*[^0-9.]//'
0.1.0.8
$ echo "$var" | awk -F'[^0-9.]' '{print $NF}'
0.1.0.8
if data in d file, tried on gnu sed:
sed -E 's/relea.*/.*([0-9][0-9.]*)$/\1/' d

how to save arithmetic expression into a variable in shell?

I want to save the number of lines minus 2 into a shell variable.
I have tried this:
eval a = wc -l meny1.xml | awk '{print $1}
tail a-2 meny1.xml >> tmp
for saving the number of line of a file and then decrease it by 2.
but it doesn't do the trick
how should I write this?
You could try something like:
$ export count=$((`wc -l < myfile` - 2))
$ echo $count
2
$ wc -l file
4
You can try something like
$ a=$(wc -l file | awk '{print $1-2}')
$ echo $a
3
$ wc -l file
5 file

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

bash: Grab fields 5 and 7 from a Unix path?

Given paths like this:
/data/mirrors/third-party/centos/5/projectA/x86_64
/data/mirrors/third-party/centos/5/projectA/i386
/data/mirrors/third-party/centos/5/projectA/noarch
/data/mirrors/third-party/centos/4/projectB/x86_64
/data/mirrors/third-party/centos/4/projectB/i386
/data/mirrors/third-party/centos/4/projectB/noarch
/data/mirrors/third-party/centos/4/projectC/x86_64
/data/mirrors/third-party/centos/4/projectC/i386
/data/mirrors/third-party/centos/4/projectC/noarch
How can I grab the values from field 5 and 7 ('5' and 'x86_64') using Bash shell commands?
I have something like this so far, but I'm looking for something more elegant, and without the need to capture the 'junk*':
cd /data/mirrors/third-party/centos/5/project/x86_64
echo `pwd` | tr '/' ' ' | while read junk1 junk2 junk3 junk4 version junk5 arch; do
echo version=$version arch=$arch
done
version=5 arch=x86_64
This works for me:
pwd | awk -F'/' '{print "version=" $6 " arch=" $8}'
You can use IFS and an array to split the directory into its components:
#!/bin/bash
saveIFS=$IFS
IFS='/'
dirs=($(pwd))
IFS=$saveIFS
version=${dirs[5]}
arch=${dirs[7]}
> p=$(pwd)
> echo $p
/data/mirrors/third-party/centos/5/projectA/x86_64
> basename ${p}
x86_64
> basename ${p%/*/*}
5
You can also use something like:
echo `expr match "$p" '<regular-expression>'`
...perhaps someone might help me with that regular expression ;)
try this
echo `pwd` | cut -d'/' -f6,8 | tr '/' ' '
to display field
or to display with sring version and arch
echo `pwd` | cut -d'/' -f6,8 | sed -e 's/\(.*\)\/\(.*\)/version=\1 arch=\2/'

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