If and else, different variables and same result - bash

My problem is that i don't understand why when I run the script if i write "yes" or "no" it always says I'm quitting the script. I know that it doesn't recognise $reply and "yes" as equal but why? (I am new in bash programming). Thanks!
#!/bin/bash
clear
echo 'This script will install: Firefox 17.0.1 (language: enGB or itIT or enUS) and flash 11 in Firefox17.0.1, continue?'
read reply
if (( "$reply" = "yes" )); then
pkill firefox
rm -rf /tmp/fox
mkdir /tmp/fox
cd /tmp/fox
rm -rf /opt/firefox/*
rm -rf /usr/lib/mozilla/plugins/*
rm -f /usr/share/icons/mozicon128.png
mkdir /usr/lib/mozilla/plugins
mkdir /opt/firefox
echo "Enter your language (exmp: it en us)"
read reply1
if (( "$reply1" = "it" )); then
wget ftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/latest/linux-x86_64/it-IT/firefox-17.0.1.tar.bz2
elif (( "$reply1" = "en" )); then
wget ftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/latest/linux-x86_64/en-GB/firefox-17.0.1.tar.bz2
else
wget ftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/latest/linux-x86_64/en-US/firefox-17.0.1.tar.bz2
fi
wget http://fpdownload.macromedia.com/get/flashplayer/pdc/11.2.202.258/install_flash_player_11_linux.x86_64.tar.gz
wget http://upload.wikimedia.org/wikipedia/commons/7/76/Mozilla_Nightly_icon_2011.png
tar -xvf firefox-17.0.1.tar.bz2
tar -xvf install_flash_player_11_linux.x86_64.tar.gz
cp -R firefox/* /opt/firefox
cp libflashplayer.so /usr/lib/mozilla/plugins/
rm -f /opt/firefox/icons/mozicon128.png
cp -f Mozilla_Nightly_icon_2011.png /opt/firefox/icons/mozicon128.png
echo "Reboot the system to show the new icon?"
read response
if (( "$response" = "yes" )); then
reboot
else
echo 'Installation Complete'
fi
else
echo "I'm quitting the script..."
exit
fi

You're using an arithmetic expression block (( )) to compare strings. Chaos will ensue.
read -p 'This script will install: Firefox 17.0.1 (language: enGB or itIT or enUS) and flash 11 in Firefox17.0.1, continue?' reply
if [[ "$reply" = "yes" ]]; then
…

Double parenthesis (( ... )), when used with an if/then construct, return an exit status according to the evaluation of the integer test expression they are embracing. For instance, the test ((5 == 5)) would evaluate true (i.e. 0).
Standalone, double parenthesis allow for you to use arithmetic evaluations like i=$(( 2+3 )), and/or c-style syntax, like
(( i = 1 )) #or
(( i++ )) #or
for ((i=0;i<5;i++)); do ...; done
However, in your code, while you are trying to evaluate variable comparison expressions, you are in fact testing against a c-style assignment. (( "$reply" = "yes" )) does neither compare integers nor any other values, but simply assigns a numerical conversion of the string "yes" to a variable identified by the content of $reply and returns the assigned value as its exit status.
yes converts to 0. In the case that a user entered yes as their reply, the effect will be the assignment
yes=0
Given that, the if statement is merely testing for an integer value to be nonzero, so since the assigned value in the parenthesis is zero, it will return a 1 as an exit code, which means false, and the then block will not be executed. Unless the user enters a nonzero integer value.
Change parenthesis to double-brackets [[...]] and you will be fine. If you prefer to use = or == as an operator doesn't matter in this case.
if [[ "$reply" = "yes" ]]; then
You will find useful answers on this site when in need for further details.

Run this script, It worked for me with no errors and got my flash player working.
# Prepare Directory's
pkill firefox
mkdir /tmp/fox
cd /tmp/fox
rm -rf /opt/firefox/*
rm -rf /usr/lib/mozilla/plugins/*
rm -f /usr/share/icons/mozicon128.png
mkdir /usr/lib/mozilla/plugins
mkdir /opt/firefox
# Download Resources
wget http://ftp.mozilla.org/pub/mozilla.org/firefox/releases/latest/linux-x86_64/en-US/firefox-18.0.tar.bz2
wget http://fpdownload.macromedia.com/get/flashplayer/pdc/11.2.202.258/install_flash_player_11_linux.x86_64.tar.gz
wget http://upload.wikimedia.org/wikipedia/commons/7/76/Mozilla_Nightly_icon_2011.png
# Extract Resources
tar -xvf firefox-18.0.tar.bz2
tar -xvf install_flash_player_11_linux.x86_64.tar.gz
# Install
cp -R firefox/* /opt/firefox
cp libflashplayer.so /usr/lib/mozilla/plugins/
#Restart Backtrack to reload start menu icon's or goto menu editor and reselect icon
cp -f Mozilla_Nightly_icon_2011.png /usr/share/icons/mozicon128.png
# Done
echo 'Installation Complete'

Related

Shell if statement executed from Makefile always evaluates to false [duplicate]

This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 7 months ago.
I need to add shell if-else statement to my Makefile, but the if expression always evaluates to false.
For example the next code:
if [1 -eq 1]; then echo "yes"; else echo "no"
prints "no"
The only code that evaluated to true was:
if true; then echo "yes"; else echo "no"
Why all expressions in the code (except for "true") evaluates to false? :(
I would really appreciate any help
** Please note - the statements work correctly when run from Shell
The code snippet from the original Makefile:
SIMULATION_RUN_CMD = rm -rf $(TEST_DIR)/* && mkdir -p $(TEST_DIR) && cd $(TEST_DIR) && (cp -rf $(VIVADO_PROJ)/$(PROJECT)/export_for_sim/$(SIMULATOR)/{*.mem,.mif,design.dat,nocattrs.dat,cpm_data_sim.cdo} $(TEST_DIR) || true) && \
ln -sf $(TEST_DIR)/simulation.log $(RUN_DIR)/simulation.log && \
(timeout $(SIM_TIMEOUT) ${SIM_DIR}/simv +UVM_TESTNAME=$(UVM_TESTNAME) $(SIM_FLAGS) -l $(TEST_DIR)/simulation.log -do $(DO_FILE) ; \
if [1 -eq 1]; then echo "if statement yes " >> $(TEST_DIR)/simulation.log; else echo "if statement no " >> $(TEST_DIR)/simulation.log; fi \
|| true) && \
$(MODEL_POST_SIM_ACIONS)
$(SIMULATION_RUN_TAR):
#echo -e "Make Command: $(SIMULATION_RUN_CMD)" $(PRINT_OUTPUT)
($(SIMULATION_RUN_CMD)) $(PRINT_OUTPUT)
First, you have a syntax error in your command. If you type that exactly into bash you'll get an error:
[[1: command not found
You need spaces after the [[ and before the ]] tokens:
if [[ 1 -eq 1 ]]; then echo "yes"; else echo "no"
Second, the reason it doesn't work when run from make is that make doesn't invoke bash. Make invokes the POSIX standard shell /bin/sh. If you do this you'll see the same behavior you get with make:
$ /bin/sh -c 'if [[ 1 -eq 1 ]]; then echo yes; else echo no; fi'
/bin/sh: 1: [[: not found
no
The [[ operator is a bash-specific feature. If you want to write this using POSIX features you should use:
$ /bin/sh -c 'if [ 1 -eq 1 ]; then echo yes; else echo no; fi'
yes
If you really want make to invoke bash as its shell instead of sh, add this to your makefile:
SHELL := /bin/bash
Of course then your makefile will not work on any system that doesn't have /bin/bash available.
ETA
After seeing the very much more complicated, but still not complete, code you added, I will say the following:
As I said above, you have an error in your script. if [1 -eq 1] is completely illegal. You must have spaces after [ and before ]. Again, if you run this yourself at the shell prompt you will get the same failure. It has nothing to do with make.
Because of this error, the if-statement will ALWAYS fail and so this will ALWAYS run the "else" command and print "no".
You say you don't see any error message. I can't explain that, except that you run this recipe this way:
($(SIMULATION_RUN_CMD)) $(PRINT_OUTPUT)
You don't tell use what the value of the PRINT_OUTPUT variable is, so I can only assume that it throws away stderr into the bit-bucket (or possibly, both stdout and stderr). If you didn't do that, so you could see the output, you'd see the error message being printed. Or maybe that redirects to a log file in which case, you can look there for the message.

Bash Script variable assigned "-r" when using rm -r $VAR

Heres the code:
function rm {
cd ~/
if [[ -d ./Jam/projects/"$1" ]]; then
echo Removing $1 from projects...
rm -r ./Jam/projects/"$1"
elif [[ -d ./Jam/archive/"$1" ]]; then
echo Removing $1 from archives...
rm -r ./Jam/archive/"$1"
else
echo $1 does not exist \in ./Jam/projects/ or ./Jam/archive
exit
fi
echo Finished\!
}
When this is ran, $1 is "Hello World" (a Directory in i./Jam/archive/)
I get this output:
Removing HelloWorld from archives...
-r does not exist in ./Jam/projects/ or ./Jam/archive
Somehow, $1 is assigned to "-r".
I don't know how on earth this would happen. Any help is much appreciated.
Your function is called "rm" and inside your function "rm" you call rm -r thinking it's "normal rm", but it isn't - it's your function, which perfectly demonstrates the danger of calling your function a name that already has a well known meaning.

Best way for conditionally (and verbosely) run a command in bash

I have written a shell script (bash) which runs some commands. It has an option to not to run the commands but to echo them to the screen. By default, the output of these commands is redirected to /dev/null but there is another option to show the output on the screen.
I use a function to check for the value of these variables and run the commands or simulate them:
runmaybe() {
if [[ true = $dry_run ]]; then
echo "Simulating '$#'"
else
if [[ true = $verbose ]]; then
$#
else
$# > /dev/null
fi
fi
}
The function is working but I had some issues with complex commands such as:
runmaybe eval svn cp $url $root/tags/$ntag -m \"Tagging revision with $ntag\"
I had to add the eval to prevent wordsplitting so svn gets the right value for the -m option.
I have some other complex commands in that script such as:
runmaybe vzctl exec 1 "( cd /var/wwww/vhosts/myhost ; php cron.php )"
runmaybe ssh -t user#$host "vzctl exec $vmid \"( /usr/local/bin/myscript )\"" 2>/dev/null
runmaybe rsync --delete --exclude=\"**/.svn/\" --exclude=\"**/.git/\" --include=*.exe --numeric-ids -a $vOpt -H $LOCAL_VM$dir $host:$REMOTE_VM$dir
Although the script is working right now, I wonder if there is a better way of doing this task.
The problem is in unquoted expansion of $#. As a rule of a thumb, if you see $, you should put it inside ". Unquoted expansions undergo word splitting and filename expansions - to prevent them, quote the expansion.
I had to add the eval
eval is evil. Do not use it.
runmaybe() {
if [[ true = $dry_run ]]; then
echo "Simulating '$*'"
# or better quote with printf in some corner cases
printf "Simulating:"
printf " %q" "$#"
printf "\n"
elif [[ true = $verbose ]]; then
"$#"
else
"$#" > /dev/null
fi
}
runmaybe svn cp "$url" "$root/tags/$ntag" -m "Tagging revision with $ntag"
runmaybe rsync --delete --exclude="**/.svn/" --exclude="**/.git/" --include="*.exe" --numeric-ids -a "$vOpt" -H "$LOCAL_VM$dir" "$host:$REMOTE_VM$dir"

Eval error Argument list too long when expandind a command

I got some code from here that works pretty well until I get "Argument list too long"
I am NOT a developer and pretty old too :) so if it is not much to ask please explain.
Is there a way the expand DIRCMD like eval does and pass each of the commands one at the time so eval does not break?
for (( ifl=0;ifl<$((NUMFIRSTLEVELDIRS));ifl++ )) { FLDIR="$(get_rand_dirname)"
FLCHILDREN="";
for (( ird=0;ird<$((DIRDEPTH-1));ird++ )) {
DIRCHILDREN=""; MOREDC=0;
for ((idc=0; idc<$((MINDIRCHILDREN+RANDOM%MAXDIRCHILDREN)); idc++)) {
CDIR="$(get_rand_dirname)" ;
# make sure comma is last, so brace expansion works even for 1 element? that can mess with expansion math, though
if [ "$DIRCHILDREN" == "" ]; then
DIRCHILDREN="\"$CDIR\"" ;
else
DIRCHILDREN="$DIRCHILDREN,\"$CDIR\"" ;
MOREDC=1 ;
fi
}
if [ "$MOREDC" == "1" ] ; then
if [ "$FLCHILDREN" == "" ]; then
FLCHILDREN="{$DIRCHILDREN}" ;
else
FLCHILDREN="$FLCHILDREN/{$DIRCHILDREN}" ;
fi
else
if [ "$FLCHILDREN" == "" ]; then
FLCHILDREN="$DIRCHILDREN" ;
else
FLCHILDREN="$FLCHILDREN/$DIRCHILDREN" ;
fi
fi
}
cd $OUTDIR
DIRCMD="mkdir -p $OUTDIR/\"$FLDIR\"/$FLCHILDREN"
eval "$DIRCMD"
echo "$DIRCMD"
}
I tried echo $DIRCMD but do not get the expanded list of commands
'echo mkdir -p /mnt/nvme-test/rndpath/"r8oF"/{"rc","XXKR","p0H"}/{"5Dw0K","oT","rV","coU","uo"}/{"3m5m","uEdA","w4SJp","49"}'
I had trouble following the code, but if I understood it correctly, you dynamically generate a mkdir -p command with a brace expansion:
'mkdir -p /mnt/nvme-test/rndpath/"r8oF"/{"rc","XXKR","p0H"}/{"5Dw0K","oT","rV","coU","uo"}/{"3m5m","uEdA","w4SJp","49"}'
Which then fails when you eval it due to your OS' maximum argument limit.
To get around that, you can instead generate a printf .. command since this is a Bash builtin and not subject to the argument limit, and feed its output to xargs:
dircmd='printf "%s\0" /mnt/nvme-test/rndpath/"r8oF"/{"rc","XXKR","p0H"}/{"5Dw0K","oT","rV","coU","uo"}/{"3m5m","uEdA","w4SJp","49"}'
eval "$dircmd" | xargs -0 mkdir -p
If your xargs doesn't support -0, you can instead use printf "%s\n" and xargs mkdir -p, though it won't behave as well if your generated names contain spaces and such.
If this is for benchmarking, you may additionally be interested to know that you can now use xargs -0 -n 1000 -P 8 mkdir -p to run 8 mkdirs in parallel, each creating 1000 dirs at a time.

Shell script to poll a directory and stop upon an event

Need shell script to:
1/keep polling a directory "receive_dir" irrespective of having files or no files in it.
2/move the files over to another directory "send_dir".
3/the script should only stop polling upon a file "stopfile" get moved to "receive_dir". Thanks !!
My script:
until [ $i = stopfile ]
do
for i in `ls receive_dir`; do
time=$(date +%m-%d-%Y-%H:%M:%S)
echo $time
mv receive_dir/$i send_dir/;
done
done
This fails on empty directories and also is there any better way ?
If you are running on Linux, you might wish to consider inotifywait
$ declare -f tillStopfile
tillStopfile ()
{
cd receive_dir
[[ -d ../send_dir ]] || mkdir ../send_dir
while true; do
date +%m-%d-%Y-%H:%M:%S
for f in *
do
mv "$f" ../send_dir
[[ $f == "stopfile" ]] && break 2
done
sleep 3
done
}
$
Improvements
while true ... break #
easier to control this loop
cd receive_dir #
why not run in the "receive_dir"
factor date out of inner loop #
unless you need to see each time-stamp?
added suggested "sleep"
# pick a suitable inteval
Run:
$ tillStopfile 2>/dev/null # suppresses ls error messages

Resources