Using sh -c if comparisons inside an SSH command - bash

I'm having some trouble with the != section of the if statement. Essentially this statement is valid as far as I'm aware, however executing this gives [: 1: !=: unexpected operator. I've tried executing using -n but for whatever reason, even if the output is blank, using -n still runs the echo command.
Any help on this is appreciated. I've attached the code snippet below.
#!/bin/sh
HOST=$1
USER="/scripts/whoowns $HOST | tr -d '\r'"
ssh -t $HOST -p 22 -l deehem "sh -c 'if [ "" != "\`$USER\`" ]; then echo "Username for $HOST: \`$USER\`"; fi' ; bash -login"

As you realised, "bla "" bla" is just two strings concatenated ("bla bla").
You can escape the ": \", but the standard [ test tool has an option specifically for this task:
-n STRING
the length of STRING is nonzero
-z STRING
the length of STRING is zero
Note: why do you have \`? That way the string is never going to be empty....

In regards to your "however executing this gives [: 1: !=: unexpected operator" problem, here is a solution:
Use bash -c instead of sh -c. The bash program seems to be better than sh at handling square brackets. For example:
ubuntu#ubuntu:/$ echo "antipetalous" | if [[ "antipetalous" =~ "ti" ]]; then echo "match"; else echo "no"; fi
match
ubuntu#ubuntu:/$ echo "antepetalous" | if [[ "antepetalous" =~ "ti" ]]; then echo "match"; else echo "no"; fi
no
ubuntu#ubuntu:/$ sh -c 'echo "antipetalous" | if [[ "antipetalous" =~ "ti" ]]; then echo "match"; else echo "no"; fi'
sh: 1: [[: not found
no
ubuntu#ubuntu:/$ bash -c 'echo "antipetalous" | if [[ "antipetalous" =~ "ti" ]]; then echo "match"; else echo "no"; fi'
match
ubuntu#ubuntu:/$ bash -c 'echo "antepetalous" | if [[ "antepetalous" =~ "ti" ]]; then echo "match"; else echo "no"; fi'
no
ubuntu#ubuntu:/$ sh -c 'echo "antepetalous" | if [[ "antepetalous" =~ "ti" ]]; then echo "match"; else echo "no"; fi'
sh: 1: [[: not found
no
ubuntu#ubuntu:/$
So ssh -t $HOST -p 22 -l deehem "sh -c 'if [ "" != ... would become ssh -t $HOST -p 22 -l deehem "bash -c 'if [ "" != ....
Thanks to pLumo at https://askubuntu.com/questions/1310106/sh-c-sh-not-working-when-using-if-statement-and-having-in-the-filena ("command line - sh -c '...' sh {} not working when using if statement and having ' in the filename - Ask Ubuntu").

Related

finding substring in string in shell script not working

I have a test.cfg file whose contents are:
product_identifier=XR656_HD;G6_656
program_family=STR
and a script file as
#!/bin/bash
CONFIG_FILE="test.cfg"
getValueforKeyInProdConfig ()
{
key=$1
if [ -e $CONFIG_FILE ]; then
value=`cat $CONFIG_FILE | grep $key | cut -d "=" -f2 | tr -d '\r'`
echo "$value"
else
echo ""
fi
}
product_identifier="$(getValueforKeyInProdConfig "product_identifier")"
program_family="$(getValueforKeyInProdConfig "program_family")"
echo "product_identifier=$product_identifier"
echo "program_family=$program_family"
if [[ ( $program_family == "STR" ) && ( ($product_identifier == *"G6_656"*) || ($product_identifier == *"G6_646"*) ) ]]; then
echo "found string"
else
echo "unknown"
fi
But the output is:
product_identifier=XR656_HD;G6_656
program_family=STR
unknown
I am expecting the output to be
found string
How should I compare substring in bash to make the script working
Why don't you just source your CONFIG_FILE?
$ cat test.cfg
product_identifier='XR656_HD;G6_656'
program_family=STR
Script
#!/bin/bash
CONFIG_FILE="test.cfg"
. "$CONFIG_FILE"
echo product_identifier=$product_identifier
echo program_family=$program_family
[[ $program_family == "STR" ]] && \
[[ $product_identifier =~ .*G6_6[45]6 ]] && \
echo "found string" || echo "unknown"
Testing
$ ./test
product_identifier=XR656_HD;G6_646
program_family=STR
found string
$ ./test
product_identifier=XR656_HD;G6_656
program_family=STR
found string
$ ./test
product_identifier=XR656_HD;G6_676
program_family=STR
unknown
$ ./test
product_identifier=XR656_HD;G6_656
program_family=fail
unknown

Bash script "Syntax Error: Unexpected end of file"

The goal is to create a simple trash utility using a Bourne shell (it's part of an assignment). I am receiving the following error: "line 17: Syntax Error: Unexpected end of file"
I have been staring at the code for a few hours now and I can't see the mistake (probably something simple I am overlooking)
#!/bin/sh
if [$# == 0] ;then
echo "Usage: trash -l | -p | { filename }*"
else
if $1 == '-l'; then
dir $HOME/.trash
else if $1=='-p'; then
rm $HOME/.trash/*
else
for i in ${} ;do
mv i $HOME/.trash
done
fi
fi
Thanks!
This is what I achieved using shellcheck:
#!/bin/sh
if [ $# -eq 0 ] ;then
echo "Usage: trash -l | -p | { filename }*"
else
if [ "$1" = '-l' ]; then
dir "$HOME"/.trash
elif "$1"=='-p'; then
rm "$HOME"/.trash/*
else
for i in ${} ;do
mv "$i" "$HOME"/.trash
done
fi

Enclosing a command in escape characters in bash

I have a command in quotes:
ssh -i "/home/$USER/$KEY" "$USER"#"$WORKER1IP" "echo 'if [[ `uname -a` == Darwin* ]]; then' >> /home/$USER/tachyon-0.5.0/conf/tachyon-env.sh"
The "uname" part has to be written literally, not executed. I tried using "\" before the 'uname' part, but I don't know how to close it. Can someone help please?
This should work:
ssh -i "/home/$USER/$KEY" "$USER"#"$WORKER1IP" "echo 'if [[ \"\$(uname -a)\" == Darwin* ]]; then' >> /home/$USER/tachyon-0.5.0/conf/tachyon-env.sh"
and this too:
ssh -i "/home/$USER/$KEY" "$USER"#"$WORKER1IP" "echo 'if [[ \`uname -a\` == Darwin* ]]; then' >> /home/$USER/tachyon-0.5.0/conf/tachyon-env.sh"
You can use $(...) with escaped $ in BASH:
ssh -i "/home/$USER/$KEY" "$USER"#"$WORKER1IP" "echo 'if [[ \$(uname -a) == Darwin* ]]; then' >> /home/$USER/tachyon-0.5.0/conf/tachyon-env.sh"
Use a here document instead, which simplifies the nested quotes.
ssh -i "/home/$USER/$KEY" "$USER#$WORKER1IP" <<EOF
echo 'if [[ $(uname -a) == Darwin* ]]; then' >> "/home/$USER/tachyon-0.5.0/conf/tachyon-env.sh"
EOF

getops still performs default actions when arguments are provided

I've recently started working with the getopts command in bash. I am confused as to why my script runs the dafult action "cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl" when arguments have been provided. I only want that to run if no arguments were passed to the shell script. I've used getopts:Std in perl where I was able to code somthing like:
unless ($opts{d}) {
do something...}
How would I code something like that in a shell script? Also, how would I code logic such as this:
if ($opts{c}) {
cat ~bin/Temp/mag.txt | ~bin/Scripts/report.pl -c
}
elsif ($opts{d} {
cat ~bin/Temp/mag.txt | ~bin/Scripts/report.pl -d
My code:
#!/bin/sh
while getopts cd name
do
case $name in
c)copt=1;;
d)dopt=1;;
*)echo "Invalid arg";;
esac
done
if [[ ! -z $copt ]] #Specifies what happens if the -c argument was provided
then
echo "CSV file created!"
cat "~/bin/Temp/log.txt" | ~/bin/Scripts/vpnreport/report.pl -c
fi
if [[ ! -z $dopt ]] #Specifies what happens if the -d argument was provided
then
echo "Debug report and files created"
cat ~bin/Temp/mag.txt | ~bin/Scripts/report.pl -d
fi
if [[ ! -z $name ]] #Specifies what happens if no argument was provided
then
echo "Running standard VPN report"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl
fi
shift $(($OPTIND -1))
My Output:
[~/bin/Scripts/report]$ sh getoptstest.sh
Running standard report
[~/bin/Scripts/report]$ sh getoptstest.sh -d
Debug report and files created
Running standard report
[~/bin/Scripts/report]$
The two getopts commands are vasty different from bash to perl and I just can't seem to get the hang of the bash varient even after reading several tutorials. Any help would be greatly appreciated!
On the final run of getopts, your variable (name) will be set to "?".
#!/bin/bash
while getopts abc foo; do :; done
echo "<$foo>"
Output of the above:
$ ./mytest.sh
<?>
$ ./mytest.sh -a
<?>
Insead, use elif, which is like Perl's elsif:
if [[ ! -z $copt ]]
then
# ...
elif [[ ! -z $dopt ]]
then
# ...
else
# ...
fi
Or test if [[ -z $copt && -z $dopt ]], or so forth. Other notes:
See the official if and case documentation in the Bash manual under "Conditional Constructs".
[[ ! -z $name ]] means the same as the more-direct [[ -n $name ]].
Use #!/bin/bash instead of #!/bin/sh, or switch off of [[ in favor of [. The double square bracket (and your use thereof) is specific to bash, and rarely works with sh.
I took Jeff's answer and rewrote my script so it works now:
#!/bin/bash
while getopts cd name
do
case $name in
c)carg=1;;
d)darg=1;;
*)echo "Invalid arg";;
esac
done
#Specifies what happens if the -c argument was provided:
if [[ ! -z $carg ]]
then
if [[ -z $darg ]]
then
echo "CSV created"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl -c
else
echo "Debug CSV created"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl -cd
fi
fi
#Specifies what happens if the -d argurment was provided:
if [[ ! -z $darg ]]
then
echo "Debug report created"
cat ~bin/Temp/log.txt | ~bin/Scripts/report.pl -d
#Specifies what happens if no argument was provided:
else
echo "Standard report created"
cat ~bin/Temp/logs.txt | ~bin/Scripts/report.pl
fi
Thank you again for your assistance!

unary operator expected with more than 1 argument

for var in "$#"
do
if test -z $var
then
echo "missing operand"
elif [ -d $var ]
then
echo "This is a directory"
elif [ ! -f $var ]
then
echo "The file does not exist"
else
basename=$(basename $var)
dirname=$(readlink -f $var)
inodeno=$(ls -i $var| cut -d" " -f1)
read -p "remove regular file $#" input
if [ $input = "n" ]
then exit 1
fi
mv $var "$var"_"$inodeno"
echo "$basename"_"$inodeno":"$dirname" >> $HOME/.restore.info
mv "$var"_"$inodeno" $HOME/deleted
fi
done
**Hello, the above code is trying to mimic the rm command in unix. Its purpose is to remove the file .
Eg if I type in bash safe_rm file1 , it works however if type in
bash safe_rm file1 file 2 , it prompts me to remove file 1 twice and gives me a unary operater expected for line 27(if [ $input = "n" ]).
Why does it not work for two files, ideally I would like it to prompt me to remove file1 and file 2.
Thanks
read -p "remove regular file $#" input
should probably be
read -p "remove regular file $var" input
That's the basic.
And this is how I'd prefer to do it:
for T in "$#"; do
if [[ -z $T ]]; then
echo "Target is null."
elif [[ ! -e $T ]]; then
echo "Target does not exist: $T"
elif [[ -d $T ]]; then
echo "Target can't be a directory: $T"
else
BASE=${T##*/}
DIRNAME=$(exec dirname "$T") ## Could be simpler but not sure how you want to use it.
INODE_NUM=$(exec stat -c '%i' "$T")
read -p "Remove regular file $T? "
if [[ $REPLY == [yY] ]]; then
# Just copied. Not sure about its logic.
mv "$T" "${T}_${INODE_NUM}"
echo "${BASE}_${INODE_NUM}:${DIRNAME}" >> "$HOME/.restore.info"
mv "${T}_${INODE_NUM}" "$HOME/deleted"
fi
fi
done

Resources