Get length of string from grep does not work - bash

I try to get the length of a string like this (bash in linux):
VAR= grep "test" file.txt
VARlength= ${#VAR}
For some reason the length is always zero, even if the string "test" is inside file.txt
Can someone explain me how to get the length of VAR and what is wrong there?

don't leave space before and after the =
you need command substitution: var=$(command)

Use $( ):
VAR=$(grep "test" test.txt)
VARlength=${#VAR}

If you like it's also possbile to use bc and wc to get the result:
VARlength=$(echo "var="$(grep "2" foo | wc -c;)";--var" | bc)
This will count the chars inside the match (wc -c) and then subtract 1 using bc, because you don't want to count the newline.

Related

print upto second last character in unix

If the length of a string is 5 then how can I print upto 4th character of the string using shell scripting.I have stored the string in a variable and length in other variable.but how can i print upto length -1.
If you are using BASH then it is fairly straight forward to remove last character:
s="string1,string2,"
echo "${s%?}"
? matches any single character and %? removes any character from right hand side.
That will output:
string1,string2
Otherwise you can use this sed to remove last character:
echo "$s" | sed 's/.$//'
string1,string2
You can do it with bash "parameter substitution":
string=12345
new=${string:0:$((${#string}-1))}
echo $new
1234
where I am saying:
new=${string:a:b}
where:
a=0 (meaning starting from the first character)
and:
b=${#string} i.e. the length of the string minus 1, performed in an arithmetic context, i.e. inside `$((...))`
str="something"
echo $str | cut -c1-$((${#str}-1))
will give result as
somethin
If you have two different variables, then you can try this also.
str="something"
strlen=9
echo $str | cut -c1-$((strlen-1))
cut -c1-8 will print from first character to eighth.
Just for fun:
When you have the string and length in vars already,
s="example"
slen=${#s}
you can use
printf "%.$((slen-1))s\n" "$s"
As #anubhava showed, you can also have a clean solution.
So do not try
rev <<< "${s}" | cut -c2- | rev

Bash: replace 4 occourance of a string if exist

I have a string that is sometimes
xxx.11_222_33_44_555.yyy
and sometimes
xxx.11_222_33_44.yyy
I would like to:
Check if has 4 occourances of _ (figured out how to do it).
If so - remove string's _33 (the 33 string changes, can be any number), so I am left with xxx.11_222_44.yyy.
Using sed :
sed 's/\(_[0-9]*\)_[0-9]*\(_[0-9]*_[0-9]*\)/\1\2/'
It matches the four underscores and replace the whole by the needed parts.
Test run :
$ echo "xxx.11_222_33_44_555.yyy" | sed 's/\(_[0-9]*\)_[0-9]*\(_[0-9]*_[0-9]*\)/\1\2/'
xxx.11_222_44_555.yyy
$ echo "xxx.11_222_33_44.yyy" | sed 's/\(_[0-9]*\)_[0-9]*\(_[0-9]*_[0-9]*\)/\1\2/'
xxx.11_222_33_44.yyy
perhaps something like this
echo "xxx.11_222_33_44.yyy" | sed -e's/\.\([0-9]\+\)_\([0-9]\+\)_\([0-9]\+\)_\([0-9]\+\)\./.\1_\2_\4./'
which checks if there are 4 groups of numbers separated by _ between the two dots and if yes, it leaves out the third group
try this;
echo "xxx.11_222_33_44_555.yyy" | awk -F'_' 'NF>4{print $1"_"$2"_"$4"_"$5};'
Solution using perl and Lookahead and Lookbehind
$ a="xxx.11_222_33_44_555.yyy"
$ perl -pe 's/\.\d+_\d+_\K\d+_(?=\d+_\d+\.)//' <<< "$a"
xxx.11_222_44_555.yyy

Remove last two path components of a path in a shell variable

I have a variable var=/usr/local/bin/test/exec
Now i have to remove last 2 path components in the above variable say:
var=/usr/local/bin/
After removing the last 2 strings I have to use this variable 'var' in a shell loop.
I tried:
var='/usr/local/bin/test/exec'
echo ${var#$(dirname "$(dirname "$s")")/}
Output:
test/exec
I am getting the truncated part as output, but I was expecting the rest of the part, not the truncated part.
You may be interested in the shell's internal substring processing operators: %, %%, # and##. Observe:
#!/bin/sh
var=/usr/local/bin/test/exec
# use shell substring processing to cut the variable down to size:
var="${var%/*}"
var="${var%/*}"
echo "$var"
# Manipulate the resulting string in a loop
for i in 1 2 3
do echo "${var}${i}"
done
OK after some googling i have found the solution for this:
var1="$(echo $var | cut -d '/' -f-4)"
If you don't know the field count, there is a standard awk solution. However, I'll show another trick using rev
var='/usr/local/bin/test/exec'; echo $var | rev | cut -d/ -f3- | rev
will give
/usr/local/bin
You can try this method also
var=/usr/local/bin/test/exec
sed 's_\(.*\)/.*/.*$_\1_' <<< $var
Another Method
sed 's_\(.*\)\(/.*\)\{2\}$_\1_' <<< $var
Output:
/usr/local/bin

How to use sed to extract a string [duplicate]

This question already has answers here:
BASH extract value after string in variable Not file [duplicate]
(2 answers)
Closed last year.
I need to extract a number from the output of a command: cmd. The output is type: 1000
So my question is how to execute the command, store its output in a variable and extract 1000 in a shell script. Also how do you store the extracted string in a variable?
This question has been answered in pieces here before, it would be something like this:
line=$(sed -n '2p' myfile)
echo "$line"
if [ `echo $line || grep 'type: 1000' ` ] then;
echo "It's there!";
fi;
Store output of sed into a variable
String contains in Bash
EDIT: sed is very limited, you would need to use bash, perl or awk for what you need.
This is a typical use case for grep:
output=$(cmd | grep -o '[0-9]\+')
You can write the output of a command or even a pipeline of commands into a shell variable using so called command substitution:
variable=$(cmd);
In comments it appeared that the output of cmd contains more lines than the type : 1000. In this case I would suggest sed:
output=$(cmd | sed -n 's/type : \([0-9]\+\)/\1/p;q')
You tagged your question as sed but your question description does not restrict other tools, so here's a solution using awk.
output = `cmd | awk -F':' '/type: [0-9]+/{print $2}'`
Alternatively, you can use the newer $( ) syntax. Some find the newer syntax preferable and it can be conveniently nested, without the need for escaping backtics.
output = $(cmd | awk -F':' '/type: [0-9]+/{print $2}')
If the output is rigidly restricted to "type: " followed by a number, you can just use cut.
var=$(echo 'type: 1000' | cut -f 2 -d ' ')
Obviously you'll have to pipe the output of your command to cut, I'm using echo as a demo.
In addition, I'd use grep and then cut if the string you are searching is more complex. If we assume there can be all kind of numbers in the text, but only one occurrence of "type: " followed by a number, you can use the command:
>> var=$(echo "hello 12 type: 1000 foo 1001" | grep -oE "type: [0-9]+" | cut -f 2 -d ' ')
>> echo $var
1000
You can use the | operator to send the output of one command to another, like so:
echo " 1\n 2\n 3\n" | grep "2"
This sends the string " 1\n 2\n 3\n" to the grep command, which will search for the line containing 2. It sound like you might want to do something like:
cmd | grep "type"
Here is a plain sed solution that uses a regualar expression to find the number in your string:
cmd | sed 's/^.*type: \([0-9]\+\)/\1/g'
^ means from the start
.* can be any character (also none)
\([0-9]\+\) are numbers (minimum one character)
\1 means it takes the first pattern it finds (and only in this case) and uses it as replacement for the whole string

how to chop last n bytes of a string in bash string choping?

for example qa_sharutils-2009-04-22-15-20-39, want chop last 20 bytes, and get 'qa_sharutils'.
I know how to do it in sed, but why $A=${A/.\{20\}$/} does not work?
Thanks!
If your string is stored in a variable called $str, then this will get you give you the substring without the last 20 digits in bash
${str:0:${#str} - 20}
basically, string slicing can be done using
${[variableName]:[startIndex]:[length]}
and the length of a string is
${#[variableName]}
EDIT:
solution using sed that works on files:
sed 's/.\{20\}$//' < inputFile
similar to substr('abcdefg', 2-1, 3) in php:
echo 'abcdefg'|tail -c +2|head -c 3
using awk:
echo $str | awk '{print substr($0,1,length($0)-20)}'
or using strings manipulation - echo ${string:position:length}:
echo ${str:0:$((${#str}-20))}
In the ${parameter/pattern/string} syntax in bash, pattern is a path wildcard-style pattern, not a regular expression. In wildcard syntax a dot . is just a literal dot and curly braces are used to match a choice of options (like the pipe | in regular expressions), so that line will simply erase the literal string ".20".
There are several ways to accomplish the basic task.
$ str="qa_sharutils-2009-04-22-15-20-39"
If you want to strip the last 20 characters. This substring selection is zero based:
$ echo ${str::${#str}-20}
qa_sharutils
The "%" and "%%" to strip from the right hand side of the string. For instance, if you want the basename, minus anything that follows the first "-":
$ echo ${str%%-*}
qa_sharutils
only if your last 20 bytes is always date.
$ str="qa_sharutils-2009-04-22-15-20-39"
$ IFS="-"
$ set -- $str
$ echo $1
qa_sharutils
$ unset IFS
or when first dash and beyond are not needed.
$ echo ${str%%-*}
qa_sharutils

Resources