Bash: illegal variable name error - bash

I am trying to extract a field from a text file using grep. I want to store the line number into a bash variable for later, but I am getting an illegal variable name error. This is part of my script:
#!/bin/csh
set echo
grep -n -m 1 "HR${4}" Tossed/length${1}/TL${1}D2R${2}-${3}TT.txt | cut -d : -f 1
To_Start=$((grep -n -m 1 "HR${4}" Tossed/length${1}/TL${1}D2R${2}-${3}TT.txt | cut -d : -f 1))
This is the output:
[maurerj1#rucc-headnode Tenengolts_Generate]$ ./flow_LBBH.sh 7 0 0 0
grep --color=auto -n -m 1 HR0 Tossed/length7/TL7D2R0-0TT.txt
cut -d : -f 1
1 #This is the right number
Illegal variable name. #why is this not working?
From what I've read, uppercase, lowercase and underscores are allowed in bash variable names, so what am I doing wrong?

I fixed the issue by changing from csh to bash, removing set echo (caused some weird issue by making all input variables into "echo")and changing from $(()) to $().

the $(( expr )) syntax is used for calculations hence the confusing message.
ex: echo $((4+4)) yields 8
you want to evaluate the result of a command, simple parenthesis will do:
To_Start=$(grep -n -m 1 "HR${4}" Tossed/length${1}/TL${1}D2R${2}-${3}TT.txt | cut -d : -f 1)
Simple reproducer to prove my point:
To_Start=$(echo a:b | cut -d : -f 1)
echo $To_Start
yields:
a

Related

Set a command to a variable in bash script problem

Trying to run a command as a variable but I am getting strange results
Expected result "1" :
grep -i nosuid /etc/fstab | grep -iq nfs
echo $?
1
Unexpected result as a variable command:
cmd="grep -i nosuid /etc/fstab | grep -iq nfs"
$cmd
echo $?
0
It seems it returns 0 as the command was correct not actual outcome. How to do this better ?
You can only execute exactly one command stored in a variable. The pipe is passed as an argument to the first grep.
Example
$ printArgs() { printf %s\\n "$#"; }
# Two commands. The 1st command has parameters "a" and "b".
# The 2nd command prints stdin from the first command.
$ printArgs a b | cat
a
b
$ cmd='printArgs a b | cat'
# Only one command with parameters "a", "b", "|", and "cat".
$ $cmd
a
b
|
cat
How to do this better?
Don't execute the command using variables.
Use a function.
$ cmd() { grep -i nosuid /etc/fstab | grep -iq nfs; }
$ cmd
$ echo $?
1
Solution to the actual problem
I see three options to your actual problem:
Use a DEBUG trap and the BASH_COMMAND variable inside the trap.
Enable bash's history feature for your script and use the hist command.
Use a function which takes a command string and executes it using eval.
Regarding your comment on the last approach: You only need one function. Something like
execAndLog() {
description="$1"
shift
if eval "$*"; then
info="PASSED: $description: $*"
passed+=("${FUNCNAME[1]}")
else
info="FAILED: $description: $*"
failed+=("${FUNCNAME[1]}")
done
}
You can use this function as follows
execAndLog 'Scanned system' 'grep -i nfs /etc/fstab | grep -iq noexec'
The first argument is the description for the log, the remaining arguments are the command to be executed.
using bash -x or set -x will allow you to see what bash executes:
> cmd="grep -i nosuid /etc/fstab | grep -iq nfs"
> set -x
> $cmd
+ grep -i nosuid /etc/fstab '|' grep -iq nfs
as you can see your pipe | is passed as an argument to the first grep command.

Executing bash -c with xargs

I had a job to perform that involved:
grep lines from a log
find a number in the line
perform basic arithmetic on the number (say, number + 1234)
The final result is a bunch of numbers separated by a newline.
If the input was:
1000
2000
3000
Then the required output was:
2234
3234
4234
I ended up with the following command:
cat log.txt | grep "word" | cut -d'|' -f7 | cut -d' ' -f5 | xargs -n 1 bash -c 'echo $(($1 + 1234))' args
I found the xargs -n 1 bash -c 'echo $(($1 + 1234))' args snippet in an answer to this question but I don't understand the need for the final args argument that is passed in. I can change it to anything, args could be blah, but if I omit it the arithmetic fails and the output is the numbers unchanged:
1000
2000
3000
Could anyone shed some light on why args is a required argument to bash -c?
A simple awk command can do the same - in a clean way:
awk -F'|' '/word/{split($7,a," "); print a[5]+1234}' log.txt
Man bash:
-c If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after
the command_string, they are assigned to the positional parameters, starting with $0.
So, for your case, 'args' is a placeholder that goes in $0, making your actual input go in $1.
You should be able to alter your command to:
grep "word" log.txt | cut -d'|' -f7 | cut -d' ' -f5 | xargs -n 1 bash -c 'echo $(($0 + 1234))'

Getting an error 'integer expression expected', while comparing two integers

# Program which notifies the User through 'notify-send' when device temperature exceeds the threshold.
#!/bin/bash
Temp=adb shell cat /sys/devices/platform/omap/omap_temp_sensor.0/temperature
if [ $Temp -gt 42000 ]
then
notify-send Temperature "$Temp " -i /usr/share/pixmaps/idle.xpm
cvlc /home/Xme/Desktop/Beep-263732.mp3
else
echo "Exit"
fi
Getting error as
: integer expression expected
I am not getting the data type of $Temp which is reading the data by Device, and how can i compare the integers, i tried if [ [$Temp > 42000] ] did not work.
As we said in the comments, this solved the issue:
Temp=$(adb shell cat /sys/devices/platform/omap/omap_temp_sensor.0/temperature) | grep -o "[0-9]*")
First of all, you were not fetching the number properly. Note that you need to use
Temp=$(command)
While you were using
Temp=command
Then we saw that your input was not integer. I guess there must be some trailing characters. To delete them, I suggest to use grep -o "[0-9]*", which just matches the numbers in the string given. EXamples:
$ echo "23 " | grep -o "[0-9]*"
23
$ echo "as23.22" | grep -o "[0-9]*"
23
22
$ echo "23" | grep -o "[0-9]*"
23

Variable expanding in a script shell

My code is:
nb_lignes=`wc -l $1 | cut -d " " -f1`
for i in $(seq $(($nb_lignes - 1)) )
do
machine=`head $1 -n $i | tail -1`
machine1=`head $1 -n $nb_lignes | tail -1`
ssh root#$machine -x " scp /home/file.txt root#$machine1:/home && rm -r /home/file.txt"
done
Is $machine1 taken as a variable or a string? If a string, how can I change it — by adding a quote?
$machine will expand to head $1 -n $i | tail -1 result, $machine1 will expand to head $1 -n $nb_lignes | tail -1 result.
You could figured it out by yourself.
Btw, ssh root# …
$machine1 will be expanded to give the value of variable machine1, because you are using double quotes". If you had used single quotes ' then it would not have been expanded.
One possible confusion is when you embed a variable inside other text. In this case you are fine, because the trailing character is a : (root#$machine1:/home) which is not a valid character in a Bash variable name. Some shells (csh) would not have liked that, if you are not sure then you can delimit the variable name using { }, for example:
root#${machine1}:/home

Unary Operator with a while loop in bash

I'm trying to get a bash script setup so it'll move files up to a specified size limit(in this case 1GB) from one directory to another. I'm trying to get it to enter the loop but I'm having issues with the while statement. It keeps returning the below output and I'm not sure why. If I try to use "$currentSize" in the while bash says it's expecting an integer comparison. But variables in bash are supposed to be untyped, so I can't cast it to an intiger, right? Any help is appropriated.
Output
54585096
1048576
./dbsFill.bsh: line 9: [: -lt: unary operator expected
Code
#!/bin/bash
currentSize= du -s /root/Dropbox | cut -f 1
maxFillSize=1048576
echo $currentSize
echo $maxFillSize
cd /srv/fs/toSort/sortBackup
while [ $currentSize -lt $maxFillSize ]
do
#fileToMove= ls -1
#rsync -barv --remove-source-files $fileToMove /root/Dropbox/sortme
# mv -t /root/Dropbox/sortme $(ls -1 | head -n 1)
#find . -type f -exec mv -t /root/Dropbox/sortme {} \;
#currentSize= du -s /root/Dropbox | cut -f 1
# sleep 5
echo Were are here
done
What you're trying to achieve by:
currentSize= du -s /root/Dropbox | cut -f 1
is to capture the current size of /root/Dropbox in currentSize. That isn't happening. That's because whitespace is significant when setting shell variables, so there's a difference between:
myVar=foo
and
myVar= foo
The latter tries to evaluate foo with the environment variable myVar set to nothing.
Bottom line: currentSize was getting set to nothing, and line 9 became:
while [ -lt 1048576 ]
and of course, -lt isn't a unary operator which is what the shell is expecting in that situation.
To achieve your intent, use Bash command substitution:
currentSize=$( du -s /root/Dropbox | cut -f 1 )
currentSize= du -s /root/Dropbox | cut -f 1
This does not do what you think it does.
currentSize=$(du -s /root/Dropbox | cut -f 1)
you need to re-write your 'currentSize ...' line as
currentSize=$(du-s /root/Dropbox | cut -f 1)
Your code left the value of currentSize empty.
You can spot such problems (with a little practice), but using the shell debugging feature
set -vx
at the top of your script, or if you think you're pretty sure where there's a problem, surround your suspiocus code like:
set -vx
myProblematicCode
set +vx
(the set +vx turns off debug mode.)
I hope this helps.

Resources