LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-02-2022, 10:36 AM   #1
lqmsh
Member
 
Registered: Oct 2021
Posts: 32

Rep: Reputation: Disabled
&& and || and && again confusing


I am trying to figure out my script to be simple
Code:
$ a=11
$ [ -z $a ] && echo empty || echo noempty && date
retruns
Code:
noempty
Tue Aug  2 09:54:17 PM +0630 2022
And

Code:
$ a=11
$ [ ! -z $a ] && echo empty || echo noempty && date
retruns
Code:
empty
Tue Aug  2 09:54:17 PM +0630 2022
Why does the second script with ! still return the output of
Code:
date
command?

Actually I am trying to change this script
Code:
#!/bin/dash

while true; do
	open=$(ls -a --group-directories-first --file-type | grep -v "^\.[a-zA-Z0-9]\|^\./" | dmenu -p "dmenuFM: ")
	if [ -d "$open" ]; then
		cd "$open"
	else
		if [ ! -z "$open" ]; then
			xdg-open "$open"
		fi
		break
	fi
done
to
Code:
#!/bin/dash

while true; do
	open=$(ls -a --group-directories-first --file-type | grep -v "^\.[a-zA-Z0-9]\|^\./" | dmenu -p "dmenuFM: ")
	[ -d "$open" ] && cd "$open" || xdg-open "$open" && break
done
But the way I am changing is not working as expected.

Last edited by lqmsh; 08-02-2022 at 10:37 AM.
 
Old 08-02-2022, 11:01 AM   #2
smallpond
Senior Member
 
Registered: Feb 2011
Location: Massachusetts, USA
Distribution: Fedora
Posts: 4,041

Rep: Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234
In bash, && and || have equal precedence and are evaluated left-to-right.
Since a is not empty:

Code:
[ ! -z $a ] && echo empty || echo noempty && date
is the same as:
Code:
true && echo empty || echo noempty && date
So the first && is not short-circuited, so prints "empty", then we have:
Code:
true || echo noempty && date
the || is short-circuited, so does not print "noempty". Then we have:
Code:
true && date
which is not short-circuited, so prints date.
 
1 members found this post helpful.
Old 08-02-2022, 04:01 PM   #3
michaelk
Moderator
 
Registered: Aug 2002
Posts: 24,745

Rep: Reputation: 5599Reputation: 5599Reputation: 5599Reputation: 5599Reputation: 5599Reputation: 5599Reputation: 5599Reputation: 5599Reputation: 5599Reputation: 5599Reputation: 5599
Basically &&, || and ; chain commands together on a single line.

To elaborate the && and || work on the exit status of the command, && if the command completed successfully and || if it does not.

The "echo string" command should always return successfully and therefore the date command is always executed.
 
Old 08-02-2022, 06:50 PM   #4
rnturn
Senior Member
 
Registered: Jan 2003
Location: Illinois (SW Chicago 'burbs)
Distribution: openSUSE, Raspbian, Slackware. Older: Coherent, MacOS, Red Hat, Big Iron IXs: AIX, Solaris, Tru64
Posts: 2,744

Rep: Reputation: 547Reputation: 547Reputation: 547Reputation: 547Reputation: 547Reputation: 547
Quote:
Originally Posted by lqmsh View Post
I am trying to figure out my script to be simple
Code:
$ a=11
$ [ -z $a ] && echo empty || echo noempty && date
retruns
[CODE]

<snip>

Code:
#!/bin/dash

while true; do
	open=$(ls -a --group-directories-first --file-type | grep -v "^\.[a-zA-Z0-9]\|^\./" | dmenu -p "dmenuFM: ")
	if [ -d "$open" ]; then
		cd "$open"
	else
		if [ ! -z "$open" ]; then
			xdg-open "$open"
		fi
		break
	fi
done
Just my US$0.02 but, assuming that the original script is actually working, taking the clear "if-then-else" constructs and trying to turn them into a one-liner may not be making the script simpler. Shorter, sure, but not necessarily simpler. Clear-and-simple-to-understand beats clever any day. Will the one-liner make sense when the script is visited again in months or a year from now?

Just tossing this into the mix: K.I.S.S.
 
Old 08-02-2022, 07:38 PM   #5
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 9,983

Rep: Reputation: 3182Reputation: 3182Reputation: 3182Reputation: 3182Reputation: 3182Reputation: 3182Reputation: 3182Reputation: 3182Reputation: 3182Reputation: 3182Reputation: 3182
Others may have provided the why?, but rnturn has provided the best answer IMHO
 
Old 08-03-2022, 03:28 AM   #6
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 20,777

Rep: Reputation: 7059Reputation: 7059Reputation: 7059Reputation: 7059Reputation: 7059Reputation: 7059Reputation: 7059Reputation: 7059Reputation: 7059Reputation: 7059Reputation: 7059
The "usual" mistake here is: the if/then/else construct cannot be replaced by && || or something similar, that works differently (there are some cases when they produce the same result and there are some other cases when they produce different result).
As it was already mentioned, if the && || && construct is confusing, use if/then/elif/else. That is much more readable and more easily understandable.
 
Old 08-03-2022, 05:25 AM   #7
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,711
Blog Entries: 1

Rep: Reputation: 1807Reputation: 1807Reputation: 1807Reputation: 1807Reputation: 1807Reputation: 1807Reputation: 1807Reputation: 1807Reputation: 1807Reputation: 1807Reputation: 1807
Or perhaps:
Code:
test -z "$a" && echo empty || { echo noempty; date; }
 
Old 08-03-2022, 09:51 AM   #8
boughtonp
Senior Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 3,402

Rep: Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451

Sometimes a parenthized sub-shell can be used to deal with order of precedence issues:
Code:
( [ -n "$a" ] && echo empty ) || ( echo noempty && date )
But that wont work with the actual code involving cd, because the directory change is lost when the sub-shell ends.


Still the actual code can be simplified...

I had expected to see someone pointing out that "! -z" is a longer way to write "-n", though that check possibly isn't even needed - an empty value comes from pressing Esc in dmenu, right? So just move the assignment into the while check and rely on the dmenu exit status to abort the loop instead.

This allows there to be a single inverted test of "not a directory" which can bring that part down to a couple of lines, (the break removes the need for an explicit else clause).

Also, the grep is unnecessary; far easier to remove the -a option so the offending items never get output, then prefix the "..".

Also I haven't checked but it may be necessary to explicitly set an ls quoting style. (This script wont handle filenames with newlines in, but that's a limitation with dmenu too?)

Code:
#!/bin/dash

while selection=$( ( echo ".." ; ls -1 --g --file-type ) | dmenu -p "dmenuFM: " )
do
   if [ ! -d "$selection" ]; then echo xdg-open "$selection" ; break ; fi
   cd "$selection" || echo "error: failed to cd [$selection] in [$PWD]"
done
 
Old 08-03-2022, 01:57 PM   #9
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,728

Rep: Reputation: 2045Reputation: 2045Reputation: 2045Reputation: 2045Reputation: 2045Reputation: 2045Reputation: 2045Reputation: 2045Reputation: 2045Reputation: 2045Reputation: 2045
Quote:
Originally Posted by boughtonp View Post
Sometimes a parenthized sub-shell can be used to deal with order of precedence issues:
Code:
( [ -n "$a" ] && echo empty ) || ( echo noempty && date )
But that wont work with the actual code involving cd, because the directory change is lost when the sub-shell ends.
I think NevemTeve's suggestion of using curly braces fixes this without having trouble with cd (since curly braces don't make sub-shells).
 
Old 08-03-2022, 04:40 PM   #10
boughtonp
Senior Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 3,402

Rep: Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451Reputation: 2451
Quote:
Originally Posted by ntubski View Post
I think NevemTeve's suggestion of using curly braces fixes this without having trouble with cd (since curly braces don't make sub-shells).
Thanks, I'm blaming that brainfart on the heat. Looks like I also forgot to switch the order of the outputs.

 
Old 08-03-2022, 06:17 PM   #11
GazL
LQ Veteran
 
Registered: May 2008
Posts: 6,727

Rep: Reputation: 4843Reputation: 4843Reputation: 4843Reputation: 4843Reputation: 4843Reputation: 4843Reputation: 4843Reputation: 4843Reputation: 4843Reputation: 4843Reputation: 4843
Looking at what the code is doing, I think I'd have gone with a 'case' construct. Maybe, something along the lines of:
Code:
while [ -z "$open" ]
do
  if open=$( ls --group-directories-first -Fd * | dmenu -p select: -l 10 ); then
    case "$open" in
      "")  :  ;;
      */)  cd "$open" ; unset open  ;;
       *)  xdg-open "$open"  ;;
    esac
  else 
    break
  fi
done

Last edited by GazL; 08-03-2022 at 06:25 PM.
 
Old 08-05-2022, 12:38 AM   #12
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Rocky 9.2
Posts: 18,309

Rep: Reputation: 2744Reputation: 2744Reputation: 2744Reputation: 2744Reputation: 2744Reputation: 2744Reputation: 2744Reputation: 2744Reputation: 2744Reputation: 2744Reputation: 2744
Another vote for rnturn - my immediate reaction was the same

Last edited by chrism01; 08-05-2022 at 12:39 AM. Reason: typo - sigh
 
Old 08-05-2022, 07:26 AM   #13
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,566

Rep: Reputation: 1124Reputation: 1124Reputation: 1124Reputation: 1124Reputation: 1124Reputation: 1124Reputation: 1124Reputation: 1124Reputation: 1124
+1 for if-then-else
Code:
if [ -n "$a" ]; then echo empty; else echo noempty; date; fi
Another suggestion for the loop:
Code:
while
  open=$(ls -a --group-directories-first --file-type | grep -v "^\.[a-zA-Z0-9/]" | dmenu -p "dmenuFM: ")
  [ -d "$open" ]
do
  cd "$open"
done
if [ -n "$open" ]
then
  xdg-open "$open"
fi

Last edited by MadeInGermany; 08-05-2022 at 07:29 AM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] virtualbox installs pcbsd again and again and again straffetoebak Linux - Virtualization and Cloud 4 11-21-2014 07:14 PM
Please configure monitor (again and again and...) Happeren SUSE / openSUSE 1 02-09-2005 07:01 AM
Dualbooting again, again, again... Procrastinator Linux - General 4 10-28-2004 11:04 AM
menudrake & kmenuedit are confusing and flaky cscott Mandriva 2 09-22-2004 11:57 PM
Need help installing Mandrake (again, again, again...) DicedMalt Mandriva 6 08-26-2003 04:47 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:11 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration