LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
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 11-02-2023, 08:42 AM   #1
czezz
Member
 
Registered: Nov 2004
Distribution: Slackware/Solaris
Posts: 931

Rep: Reputation: 44
[BASH] Nested IF in oneliner format


Hi,
Im trying to convert following IF to oneliner (format without specifying "IF" itself)
Code:
if [ -d /tmpx/ ]; then
        echo "OK1"
        COUNT=$(ls -1 /tmp/*.gz | wc -l);
        if  [ $COUNT -lt 19 ]; then
               echo "OK2"
        else
                echo "nOK2"
        fi;
else
        echo "nOK1"
fi;
I tried that but that doesnt work as intended.
Code:
[ -d /tmp/ ] && echo "OK1";  COUNT=$(ls -1 /tmp/*.gz | wc -l); [ $COUNT -lt 19 ] && echo "OK2" || echo "nOK2" || echo "nOK1"
It ignores external/last else condition.
Is there anyway to write it in this style?
 
Old 11-02-2023, 09:18 AM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,880
Blog Entries: 1

Rep: Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871
Don't modify the script only replace the line-ends with semicolons:
Code:
tr '\n' ';' <multiline.sh >singleline.sh
 
Old 11-02-2023, 09:48 AM   #3
boughtonp
Senior Member
 
Registered: Feb 2007
Location: UK
Distribution: Debian
Posts: 3,625

Rep: Reputation: 2556Reputation: 2556Reputation: 2556Reputation: 2556Reputation: 2556Reputation: 2556Reputation: 2556Reputation: 2556Reputation: 2556Reputation: 2556Reputation: 2556

Except do modify that script because it's an ugly way of checking whatever it is you're checking.

Consider...
Code:
[ ! -d /tmpx/ ] && { echo "missing directory" > /dev/stderr ; exit 1 ; }
[ "$(find /tmp/ -name '*.gz' -printf 'x' | wc -c)" -ge 19 ] && { echo "too many files" > /dev/stderr ; exit 1 ; }
echo "OK"
Depending on whatever unidentified task is actually being done here, logrotate may be a better choice.

And checking scripts with ShellCheck is always a good idea.

 
Old 11-02-2023, 10:26 AM   #4
czezz
Member
 
Registered: Nov 2004
Distribution: Slackware/Solaris
Posts: 931

Original Poster
Rep: Reputation: 44
Thanks @NevemTeve and @boughtonp for your relies.
This is however not the point.

What I am looking for is to rewrite the nested IF statement into form without "IF", using only [ ].
 
Old 11-02-2023, 11:57 AM   #5
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,781

Rep: Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935
I would ask why because IMHO as posted it is easier for my simple mind to understand. For nested tests that duplicate if-then else clauses you need to add parenthesis which is what boughtonp posted but improved. Untested but here is your code.

Code:
 [ -d /tmpx/ ] && { echo "OK1";  COUNT=$(ls -1 /tmp/*.gz | wc -l); [ $COUNT -lt 19 ] && echo "OK2" || echo "nOK2"; } || echo "nOK1"
Technically what the OP posted isn't a syntax error just logic.

Last edited by michaelk; 11-02-2023 at 12:01 PM.
 
1 members found this post helpful.
Old 11-02-2023, 11:58 AM   #6
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,269
Blog Entries: 24

Rep: Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206
Agree this is an ugly way of doing it, which causes me to wonder "why?", but will do what you ask...

Code:
[ -d /tmp/ ] && (echo "OK1";  COUNT=$(ls -1 /tmp/*.gz | wc -l); ([ $COUNT -lt 19 ] && echo "OK2" || echo "nOK2")) || echo "nOK1"
It probably helps to break it up visually...

Code:
[ -d /tmp/ ] && \
        (echo "OK1";  COUNT=$(ls -1 /tmp/*.gz | wc -l); \
                ([ $COUNT -lt 19 ] && echo "OK2" || echo "nOK2") \
        ) \
|| echo "nOK1"
 
Old 11-02-2023, 11:59 AM   #7
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,027

Rep: Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343
if/then/else cannot be replaced by && ||, they are simply not identical.
Otherwise you might need to use { } or ( ) , you can try something like this:
Code:
[ -d /tmp/ ] && { echo "OK1";  COUNT=$(ls -1 /tmp/*.gz | wc -l); [ $COUNT -lt 19 ] && echo "OK2" || echo "nOK2"; } || echo "nOK1"
 
1 members found this post helpful.
Old 11-02-2023, 12:20 PM   #8
czezz
Member
 
Registered: Nov 2004
Distribution: Slackware/Solaris
Posts: 931

Original Poster
Rep: Reputation: 44
Yes! Thank you guys for your help.

Purpose of having it that way in short: only if DIR /tmp exists, execute inner condition, otherwise skip.
Why this is ugly or wrong logic?
 
Old 11-02-2023, 12:22 PM   #9
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,828

Rep: Reputation: 1216Reputation: 1216Reputation: 1216Reputation: 1216Reputation: 1216Reputation: 1216Reputation: 1216Reputation: 1216Reputation: 1216
You can convert a if-then-fi to a && { list; }
But a if-then-else-fi can be converted to a && { list; } || { list; } only if the first { list; } does not alter its initial exit status.
Note1:
there must be a semicolon or a newline before the closing }
Code:
[ -d /tmpx/ ] && {
        echo "OK1"
        COUNT=$(shopt -s nullglob; set -- /tmp/*.gz; echo $#)
        [ $COUNT -lt 19 ] && { echo "OK2"; } || { echo "nOK2"; }
        true # The initial exit status was true(0, success)
} || {
        echo "nOK1"
}
Note2:
The echo "OK2" is always true; no true command needed here.
Note3:
The true command is not needed here because the previous statement is always true (both branches have an echo).

A if-then-else-fi is simpler.

Last edited by MadeInGermany; 11-02-2023 at 12:25 PM.
 
Old 11-02-2023, 03:25 PM   #10
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,880
Blog Entries: 1

Rep: Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871
> Purpose of having it that way in short: only if DIR /tmp exists, execute inner condition, otherwise skip.

That doesn't really explain why should it be single-line or without `if`
 
Old 11-02-2023, 04:24 PM   #11
astrogeek
Moderator
 
Registered: Oct 2008
Distribution: Slackware [64]-X.{0|1|2|37|-current} ::12<=X<=15, FreeBSD_12{.0|.1}
Posts: 6,269
Blog Entries: 24

Rep: Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206Reputation: 4206
Quote:
Originally Posted by czezz View Post
Yes! Thank you guys for your help.

Purpose of having it that way in short: only if DIR /tmp exists, execute inner condition, otherwise skip.
^^ What NevemTeve says.

Quote:
Originally Posted by czezz View Post
Why this is ugly or wrong logic?
"Ugly" in that you cannot easily understand the intended logic simply by looking at it, whereas the (possibly nested) IF/ELSE makes the logic explicit.

Wrong logic in that [...] && ... || alone is not equivalent to IF/ELSE.

Code:
if [...] then
    First whatever is here...
else
    Second whatever is here...
fi

[...] && (First whatever is here...)
|| (Second whatever is here...)
In the IF/ELSE implementation the Second whatever is here depends ONLY on the [...] test.

In the [...] && ... || implementation Second whatever is here depends on both the [...] test AND the exit status of the First whatever is here...

You can write it such that the end result is more or less equivalent for a specific case, as above, but that only makes it fragile and more obscure, or dare I say, uglier.

Last edited by astrogeek; 11-02-2023 at 04:49 PM.
 
Old 11-02-2023, 05:29 PM   #12
czezz
Member
 
Registered: Nov 2004
Distribution: Slackware/Solaris
Posts: 931

Original Poster
Rep: Reputation: 44
Smile

OK, i see the point now.
That condition will be added to the crontab and for any cost i do want to avoid adding script.
Also, i find it nicer having "no-if" statement in the oneliner

Side question - does this way of putting IF statement has its name? Does anyone know?
 
Old 11-02-2023, 05:47 PM   #13
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,683
Blog Entries: 4

Rep: Reputation: 3947Reputation: 3947Reputation: 3947Reputation: 3947Reputation: 3947Reputation: 3947Reputation: 3947Reputation: 3947Reputation: 3947Reputation: 3947Reputation: 3947
While this thread is "superficially interesting, in a geek-y sort of way," I would almost beg you to please "keep it as a separate file."

You can write the file in "bash" if you want to, or(!) you can use the so-called "shebang (#!)" feature. If, for example, the first line of your file is: #!/usr/bin/perl, the remainder of your "shell" script can now be written in [Perl]. Or any interpreted language-processor of your pleasure. The shell silently forks an instance of the appropriate interpreter, and the end-user will never know. (Or, care.)

The problem with "one-liners" is: "interpreting them, either when you did not write them, or six weeks after you did."

A "double trouble" with them is – "finding the bug(s)," and maybe first figuring out which "set of chicken-scratches" actually contains the bug(s). ("Triple trouble" if you guessed wrong.) ("Quadruple trouble" if your intended repair introduces another bug(s).) All of this wasted time is avoidable. And expensive.

A "separate file" can be written in the most-clear language of your choosing, and it can include descriptive comments. This clarity and maintainability can make all the difference in the world – yet it makes no difference at all to the computer.

Last edited by sundialsvcs; 11-02-2023 at 05:50 PM.
 
Old 11-02-2023, 06:15 PM   #14
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,781

Rep: Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935Reputation: 5935
I am not familiar with it.
 
Old 11-03-2023, 01:26 AM   #15
pan64
LQ Addict
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 22,027

Rep: Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343Reputation: 7343
Quote:
Originally Posted by czezz View Post
OK, i see the point now.
As it was mentioned it is not really a good idea, && and || is not the same as if/then/else even if sometimes looks similar or you may force them to behave similarly.
Quote:
Originally Posted by czezz View Post
That condition will be added to the crontab and for any cost i do want to avoid adding script.
Putting one-liners into crontab is not a good idea too, instead, it is meant to start a script which will do the real job. But otherwise [obviously] it can be done, it just hurts readability and maintainability
Quote:
Originally Posted by czezz View Post
Also, i find it nicer having "no-if" statement in the oneliner
As long as you don't need to work with it. Again, it just hurts readability and maintainability and against the original concept.
Quote:
Originally Posted by czezz View Post
Side question - does this way of putting IF statement has its name? Does anyone know?
&& and || are two operators, called and and or
see for example here: https://tecadmin.net/bash-logical-operators/ (sometimes they call it boolean operators).

You missed any kind of error handling which is most probably not important for you (or in this case), but not really manageable in a oneliner.
Additionally (as it was already mentioned) you don't need ls at all, you can use the shell itself to count the files.
Also you can simplify the nested if/then/else structures
Code:
[[ -d /tmp/ ]] || { echo "no dir"; exit 1; }
shopt -s nullglob
files=(/tmp/*.gz)
[[ ${#files[@]} -lt 19 ]] || { echo too many files; exit 1; }
echo ok
 
  


Reply



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
converting a bash script to a oneliner aristosv Linux - Newbie 3 10-12-2016 12:35 PM
[SOLVED] [Python] Oneliner to convert [(2,), (6,), (10,)] style return values to [2, 6, 19] brianmcgee Programming 2 11-21-2011 10:32 AM
Sed wizard wanted to write oneliner shy_guest Linux - Newbie 7 09-15-2009 09:25 PM
oneliner to launch an application in a specified directory wilsonsamm Linux - General 1 04-12-2009 10:43 AM
help with filesys oneliner chr15t0 Linux - General 3 08-24-2003 09:49 AM

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

All times are GMT -5. The time now is 04:26 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