98

I would like to have the equivelant of the following in a one line if/else condition.

$maxline=`cat journald.conf | grep "#SystemMaxUse="`
if [ $maxline == "#SystemMaxUse=" ]
then
    sed 's/\#SystemMaxUse=/SystemMaxUse=50M/g' journald.conf > journald.conf2
    mv journald.conf2 journald.conf;
else
    echo "This file has been edited. You'll need to do it manually."
fi  

I'm attempting to put this into a one line command. So far I've gotten it all but the else portion of the command. Here's what I have so far...

maxline=`cat journald.conf | grep "#SystemMaxUse="` && if [ $maxline == "#SystemMaxUse=" ]; then sed 's/\#SystemMaxUse=/SystemMaxUse=50M/g' journald.conf > journald.conf2 && mv journald.conf2 journald.conf; fi

So how can I include the else portion of the above code into my command? Thank you for your help in advance.

8 Answers 8

87

It looks as if you were on the right track. You just need to add the else statement after the ";" following the "then" statement. Also I would split the first line from the second line with a semicolon instead of joining it with &&.

maxline='cat journald.conf | grep "#SystemMaxUse="'; if [ $maxline == "#SystemMaxUse=" ]; then sed 's/\#SystemMaxUse=/SystemMaxUse=50M/g' journald.conf > journald.conf2 && mv journald.conf2 journald.conf; else echo "This file has been edited. You'll need to do it manually."; fi

Also in your original script, when declaring maxline you used back-ticks "`" instead of single quotes "'" which might cause problems.

Sign up to request clarification or add additional context in comments.

3 Comments

using single quotes breaks the code; what you really want in order to be clear is double quotes and a subshell: $maxline="$(cat journald.conf | grep '#SystemMaxUse=')"
$maxline= isn't a valid assignment at all in shell -- $ is only legal syntax on expansion, not assignment. (That said, if the goal is the run the pipeline and assign its output, one indeed wants either backticks or its modern replacement, $( ))
@CharlesDuffy a, $ was my PS1, forgot to cut it off; thanks
79

To summarize the other answers, for general use:

Multi-line if...then statement

if [ foo ]; then
    a; b
elif [ bar ]; then
    c; d
else
    e; f
fi

Single-line version

if [ foo ]; then a && b; elif [ bar ]; c && d; else e && f; fi

Using the OR operator

( foo && a && b ) || ( bar && c && d ) || e && f;

Notes

Remember that the AND and OR operators evaluate whether or not the result code of the previous operation was equal to true/success (0). So if a custom function returns something else (or nothing at all), you may run into problems with the AND/OR shorthand. In such cases, you may want to replace something like ( a && b ) with ( [ a == 'EXPECTEDRESULT' ] && b ), etc.

Also note that ( and [ are technically commands, so whitespace is required around them.

Instead of a group of && statements like then a && b; else, you could also run statements in a subshell like then $( a; b ); else, though this is less efficient. The same is true for doing something like result1=$( foo; a; b ); result2=$( bar; c; d ); [ "$result1" -o "$result2" ] instead of ( foo && a && b ) || ( bar && c && d ). Though at that point you'd be getting more into less-compact, multi-line stuff anyway.

3 Comments

The two single line versions are completely different from the original Multiline.
This is wrong for zsh: "( and [ are technically commands, so whitespace is required around them." Try (false && true)||echo 'hi'
Not just zsh: For ( and ), it's also wrong for bash. On the other hand, [ is a command in zsh as well, and [hi] is just as illegal as a replacement for [ hi ] in zsh as it is in bash.
9

It's not a direct answer to the question but you could just use the OR-operator

( grep "#SystemMaxUse=" journald.conf > /dev/null && sed -i 's/\#SystemMaxUse=/SystemMaxUse=50M/g' journald.conf ) || echo "This file has been edited. You'll need to do it manually."

Comments

6

Nice alternative to if/then/else is this construction:

[[ test_expression ]] && code_if_ok || code_if_fail

It's perfectly suits for some simple cases. Here is an example:

$ true && echo ok || echo fail
ok

$ false && echo ok || echo fail
fail

But there is a catch if code_if_ok failed for some reason code_if_fail will also be executed but in most cases that's not what we expect, check this out:

$ true && { echo ok; false;} || echo fail
ok
fail

Of course this could be workarounded like this:

$ true && { echo ok; false; true;} || echo fail
ok

We put true command at the and of our code_if_ok part to make it end with 0 exit code and prevent code_if_fail part to start. So your code could be rewritten like this:

grep -q '#var=' f && { sed 's|#\(var=\).*|\1val|g' f > f2; mv f{2,}; true;} || echo 'file edited'

2 Comments

"Here's a sometimes-right thing", and then burying the details about how it's sometimes buggy down in the body text, is a practice I'm not so sure about. Wouldn't it be better to put the most reliable/robust approach (if [[ test_expression ]]; then code_if_ok; else code_if_fail; fi) first so even tl;dr folks see it, and hide the conditionally-useful ones below where only people willing to read the text describing the conditions when they should and shouldn't be applied will see them?
Imo the text it's not that big to miss the caution sign.
4

You can use like bellow:

(( var0 = var1<98?9:21 ))

the same as

if [ "$var1" -lt 98 ]; then
   var0=9
else
   var0=21
fi

extends

condition?result-if-true:result-if-false

I found the interested thing on the book "Advanced Bash-Scripting Guide"

1 Comment

The ABS is rightly controversial (rarely updated, full of bad-practice examples); the Wooledge BashGuide was written in response specifically because the #bash IRC channel got fed up with how many bugs we were fielding from people who "learned" from the ABS.
3

I am building a script to see whether my multiline shell script is valid since I need to verify whether a Linux directory exists in my situation.

!/bin/sh
if [ -d "/var/www/html/" ] 
then
   echo "html Directory exists"
else
  echo "html Directory not exist"
  exit 1
fi

You must adhere to this syntactic structure if you wish to create the same sort of script or condition on a single line.

if [ -d "/var/www/html/" ]; then echo "html Directory exists"; else echo "html Directory not exist "; fi

Comments

2

The others answered your question, but not your specific situation. You've got cat going into grep going into a variable before we even get to the question; what you're really asking is 'how to conditionally edit a file'.

You could do this all in sed, either with some bash:

sed -n '/^#SystemMaxUse=$/Q1' journald.conf && echo "This file has been edited. You'll need to do it manually." || sed -i 's/^#\(SystemMaxUse=\)$/\150M/' journald.conf

or no bash:

sed -ni journald.conf -e 'H;${x;s/^#\(SystemMaxUse=\)$/\150M/m;ta;s/\n\(.*\)/\1/p;s/.*/This file has been edited. You'll need to do it manually./;w /dev/stdout' -e 'q;:a;s/\n\(.*\)/\1/p}'

but for editing files, vim is really the tool to reach for:

vim journald.conf -c 'norm /^#SystemMaxUse=$^MxA50M^[ZZ' -c '!echo "This file has been edited. You’ll need to do it manually."' -c q

which will make the change if it finds a line with #SystemMaxUse= on its own, or it will say

This file has been edited. You’ll need to do it manually. 

Press ENTER or type command to continue

and exit when they type any key. note that ^M and ^[ are enter and escape, and that U+2019 is used as the apostrophe.

Comments

2

I recently saw the following. example, if you are not root make $var with a value

[[ $(id -u) -ne 0 ]] && var='you are not root user'

1 Comment

I don't see in what respect this answer is related to the question. There is nothing related to the uid in the question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.