set variable in heredoc section - bash

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...

Related

Different output of command substitution

Why does adding | wc -l alters the result as in the following?
tst:
#!/bin/bash
pgrep tst | wc -l
echo $(pgrep tst | wc -l)
echo $(pgrep tst) | wc -l
$ ./tst
1
2
1
and even
$ bash -x tst
+ wc -l
+ pgrep tst
0
++ pgrep tst
++ wc -l
+ echo 0
0
++ pgrep tst
+ echo
pgrep and subshells can have weird interactions, but in this case that's just a red herring; the actual cause is missing double-quotes around the command substitution:
$ cat tst2
#!/bin/bash
pgrep tst | wc -l
echo "$(pgrep tst | wc -l)"
echo "$(pgrep tst)" | wc -l
$ ./tst2
1
2
2
What's going on in the original script is that in the command
echo $(pgrep tst) | wc -l
pgrep prints two process IDs (the main shell running the script, and a subshell created to handle the echo part of the pipeline). It prints each one as a separate line, something like:
11730
11736
The command substitution captures that, but since it's not in double-quotes the newline between them gets converted to an argument break, so the whole thing becomes equivalent to:
echo 11730 11736 | wc -l
As a result, echo prints both IDs as a single line, and wc -l correctly reports that.
The command substitution induces an additional process that has tst in its name, which is included in the input to wc -l.

Wordcount list in 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"

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

How do I echo $command without breaking the layout

I'm trying to do the following in a bash script:
com=`ssh host "ls -lh"`
echo $com
It works, but the echo will break the output (instead of getting all lines in a column, I get them all in a row).
If I do: ssh host ls -lh in the CLI it will give me the correct output and layout.
How can I preserve the layout when echoing a variable?
You need:
echo "$com"
The quotes make the shell not break the value up into "words", but pass it as a single argument to echo.
Put double quotes around $com:
com=`ssh host "ls -lh"`
printf "%s" $com | tr -dc '\n' | wc -c # count newlines
printf "%s" "$com" | tr -dc '\n' | wc -c
echo "$com"

Resources