Wordcount list in bash - bash

I am trying to count words in a list. This works :
echo "$list" | wc -w
But when I want to place this in a variable I get zero:
i="$lijst" | wc -w
echo i

Put your code inside $() or backticks , so that the code get parsed.
i=$(echo "$list" | wc -w)
echo "$i"

Related

Saving grep output to variable changes value

I want to use grep to determine if a string contains a substring. (The plan is to use that result as the test command in a bash if statement.)
Here, I check the length of the output of grep . :
$ echo "abc" | grep "j" | wc -c
0
Since wc -c shows zero, I know that grep returned an empty string.
But if I save output from grep to a variable before calling wc -c, I get a different value:
$ match=$(echo "abc" | grep "j")
$ echo "$match" | wc -c
1
The output from grep now is a string with 1 character in it.
I suspect that it's a newline in there:
$ echo $match
$
Why is there now an extra character in $match, and how can I keep that from happening?
match does not contain a newline, but echo "$match" writes a newline (but see note below). In the first case, you are directly passing the output of grep to wc, but in the second case you are passing the output of grep plus a newline to wc.
But don't do this at all. There is no need to introduce wc into the problem. Just test the value returned by grep. eg:
if ... | grep -q "$pattern"; then echo "$pattern was found in the input"; fi
Note, echo "$match" is bad practice. For example, consider if $match expands to the string -e or -n. It is much more robust to use printf '%s' "$match"
Consider the following:
$ echo "$match" | od -c
0000000 \n
0000001
$ echo "$match" | wc -c
1
$ printf "$match" | od -c
0000000
$ printf "$match" | wc -c
0
The only difference in the 2 commands is that echo appends a \n on the end of the ouput.
Of course, we can make the printf generate the same result by explicitly adding a \n on the end:
$ printf "$match\n" | od -c
0000000 \n
0000001
$ printf "$match\n" | wc -c
1

Counting grep results

I'm new to bash so I'm finding trouble doing something very basic.
Through playing with various scripts I found out that the following script prints the lines that contain the "word"
for file in*; do
cat $file | grep "word"
done
doing the following:
for file in*; do
cat $file | grep "word" | wc -l
done
had a result of printing in every iteration how many times did the "word" appeared on file.
How can I implement a counter for all those appearances and in the
end just echo the counter?
I used a counter that way but it appeared 0.
let x+=cat $filename | grep "word"
You can pipe the entire loop to wc -l.
for file in *; do
cat $file | grep "word"
done | wc -l
This is a useless use of cat. How about:
for file in *; do
grep "word" "$file"
done | wc -l
Actually, the entire loop is unnecessary if you pass all the file names to grep at once.
grep "word" * | wc -l
Note that if word shows up more than once on the same line these solutions will only count the entire line once. If you want to count same-line occurrences separately you can use -o to print each match on a separate line:
grep -o "word" * | wc -l
The oneliner in John's answer is the way to go. Just to satisfy your curiosity:
sum=0
for f in *; do
x="$(grep 'word' "$f" | wc -l)"
echo "x: $x"
(( sum += x ))
done
echo "sum: $sum"
If the line containing the grep and wc does not yield a number you are SOL. That is why you should stick to the other solution or do a pure bash implementation with things like read, 'case and *word*)' or if [[ "$line" =~ "$re_containing_word" ]]; then ...

Error "integer expression expected" in script

WBINFO="/usr/bin/wbinfo -t"
TMP="/tmp/winbind"
RESTART="/sbin/service winbind restart"
TXT="failed"
$WBINFO > $TMP
TARGET='cat $TMP |grep $TXT | wc -l'
if [ "$TARGET" -eq "1" ];
then
$RESTART
else
echo good
fi
I get this error:
line 10: [: cat $TMP |grep $TXT | wc -l: integer expression expected
Single-quoted strings don't expand $FOO into the contents of the variable FOO. Use double-quotes (").
Further, it looks like you're wanting the contents of TARGET to be the output of the cat command. If so, you probably want:
TARGET=$(cat "$TMP" | grep "$TXT" | wc -l)
Even further further, cat file | grep pattern is suboptimal - grep knows how to take files as arguments to parse rather than invoking cat, which is an whole other process to spawn. You probably really want:
if [[ $( grep -c "$TXT" "$TMP" ) -eq 1 ]]; then
TARGET='cat $TMP |grep $TXT | wc -l'
This assigns the literal string 'cat $TMP |grep $TXT | wc -l' to the variable $TARGET.
It looks like what you want is the output of the command, which requires backticks:
TARGET=`cat $TMP |grep $TXT | wc -l`
or, if you have a reasonably modern shell, the $(...) syntax:
TARGET=$(cat $TMP |grep $TXT | wc -l)
Furthermore, that command can be simplified considerably, from the above to this:
TARGET=$(grep $TXT $TMP | wc -l)
to this:
TARGET=$(grep -c $TXT $TMP)
Finally, the $TARGET variable can be eliminated altogether if you change the if statement from this:
if [ "$TARGET" -eq "1" ];
to this:
if [ $(grep -c "$TXT" "$TMP") = 1 ];
Or you can use [[ ... ]] rather than [ ... ] (it's preferred for bash).
Or, if you only care whether the pattern occurs at all (rather than requiring it to appear exactly once):
if grep -q "$TXT" "$TMP";
For that matter, you can eliminate the $TMP file as well; I'll leave that as an exercise. 8-)}
Consult the documentation for grep to see what the options do. (The -c option tells it to print the number of matches, -q prints nothing but still sets the status to indicate whether the pattern was found).
Note that I also added quotation marks around the variable references, which is good practice if there's any possibility that their values might contain any special characters.
change this line
TARGET='cat $TMP |grep $TXT | wc -l'
to
TARGET=$(cat $TMP |grep $TXT | wc -l)
or
TARGET=`cat $TMP |grep $TXT | wc -l`

simple string comparison in bash

I'm looking to get the number of subdirectories within a directory and compare that with a predefined number.
Ex:
cd /Applications/
x=echo ls -d */ | wc -l | sed 's/^ *//g'
y="52"
if [ "$x" == "$y" ]; then
echo "equal"
else
echo "not equal"
fi
It will give me a number for x (52 in my case), but will always say "not equal". What am I doing wrong? Any help would be greatly appreciated.
Thanks
For bash, do this:
cd /Applications/
dirs=( */ ) # dirs is an array with the names of directories here
if (( ${#dirs[#]} == $y )); then
echo "equal"
else
echo "not equal"
fi
Replace
x=echo ls -d */ | wc -l | sed 's/^ *//g'
with:
x="$(ls -d */ | wc -l | sed 's/^ *//g')"
Explanation: When you write x=echo ls -d */ ..., bash thinks that you mean to temporarily set the the variable x to a value of "echo" and then run the ls command. You, instead, want to run the command s -d */ | wc -l | sed 's/^ *//g' and save the output in x. The construct x=$(...) tells bash to execute whatever was in the parens and assign the output to x.
Also, bash's [ command does not accept ==. Use = for string comparison. However, you really want mathematical comparison. So use '-eq':
if [ "$x" -eq "$y" ]; then

set variable in heredoc section

I'm a shell script newbie, so I must be doing something stupid, why won't this work:
#!/bin/sh
myFile=$1
while read line
do
ssh $USER#$line <<ENDSSH
ls -d foo* | wc -l
count=`ls -d foo* | wc -l`
echo $count
ENDSSH
done <$myfile
Two lines should be printed, and each should have the same value... but they don't. The first print statement [the result of ls -d foo* | wc -l] has the correct value, the second print statement is incorrect, it always prints blank. Do I need to do something special to assign the value to $count?
What am I doing wrong?
Thanks
#!/bin/sh
while read line; do
echo Begin $line
ssh $USER#$line << \ENDSSH
ls -d foo* | wc -l
count=`ls -d foo* | wc -l`
echo $count
ENDSSH
done < $1
The only problem with your script was that when the heredoc token is not quoted, the shell does variable expansion, so $count was being expanded by your local shell before the remote commands were shipped off...

Resources