1

Here's what I'm trying to achieve.

#!/bin/bash
safemode=on

if [ $safemode == 'off' ];then
  run dangerous code
fi

I have 129 dangerous lines that are all separated. What's the best way to do this?

4
  • Sounds similar to this: unix.stackexchange.com/q/555489/70524
    – muru
    Nov 2, 2021 at 9:01
  • "Best way" is a rather broad category. Are you willing to add some minimal code to each dangerous line? Are there "groups of dangerous lines" that would need to be switched on or off "en bloc"?
    – AdminBee
    Nov 3, 2021 at 8:16
  • 1
    I'm not sure I understand what the issue is here, or what "all separated" means, or what the context for "best way" is.
    – Kusalananda
    Nov 3, 2021 at 9:37
  • [ "$safemode" = "off" ] && run dangerous code
    – Saboteur
    Nov 3, 2021 at 11:49

3 Answers 3

3

"Best way" strongly depends on how much effort you consider the maximum. One rather easy way is to use &&-connected command lists for a slight modification of your example. You can use either Bash's arithmetic test construct:

#!/bin/bash
safemode=1

(( ! safemode )) && run dangerous code 1
uncritical code
(( ! safemode )) && run dangerous code 2

or the normal string-based operator

#!/bin/bash
safemode=on

[[ $safemode = "off" ]] && run dangerous code 1
uncritical code
[[ $safemode = "off" ]] && run dangerous code 2

This is merely a rather short-hand notation for what you did already: The [[ ... ]] test will yield false if safemode is not off, hence the execution of the command list will stop at the &&.

It might be worth noting that in case of a &&-chained command list, the exit code will be that of the last command executed, so if safemode is set, the $? will be 1 after such "protected" lines (just in case you use the exit code in that way).

0
2

If we define a variable safemode to be one of the two commands true or false, then we can use that as a prefix:

#!/bin/sh
safemode=true

safe_mode_off() { safemode=false }

"$safemode" || run dangerous code 1
uncritical code
"$safemode" || run dangerous code 2

I guess we'd normally set the variable from our options processing, so true/false is as easy as on/off.


We could perhaps extend this (though I don't necessarily think we should) to just make the dangerous commands become the arguments to false, like this:

#!/bin/sh
risky=false

safe_mode_off() { risky= }

$risky run dangerous code 1
uncritical code
$risky run dangerous code 2

However in this case, expansion will still take place within the arguments - e.g. $(dangerous subcommand) would still be executed, so we'd need to change that to $($risky dangerous subcommand). I think that's too error-prone for serious use.

2
  • risky='false &&' and $risky ... works, but not because of the &&. The shell doesn't parse operators like && from the result of an expansion, so the && just gets passed as an argument to false (and ignored). You'll see that if you try risky="echo &&", and you could just set risky=false to get the same effect as risky="false &&" gives. While I said it works with false like that, there's still the fact that any expansions in the "dangerous" line still run, so something like $risky echo dangerous $(date >&2) would run the date, but not the echo.
    – ilkkachu
    Nov 16, 2021 at 11:56
  • Oops, you're right, and my tests weren't enough to uncover that. I'll mention the command expansions, too. Nov 16, 2021 at 12:01
2

If you want a shorthand, you could use an alias. They're more like text replacement than any regular expansions, so syntax constructs can be inserted through them. Just need to explicitly enable in Bash scripts, and you want to make sure to not accidentally enable unwanted aliases too.

#!/bin/bash
unalias -a
shopt -s expand_aliases

# default safe
alias risky='[ "$riskymode" = enabled ] &&'
riskymode=
if [ "$1" = risky ]; then
        riskymode=enabled
fi

echo this is normal
risky echo this is risky

But note that there's still the caveat that the condition is still just part of an &&-list, so this:

risky echo try something risky || echo oopsie it failed

would run the echo oopsie even if riskymode is disabled.

But you could do:

risky ( echo try something risky || echo oopsie it failed )

or even

risky if ! echo another risky attempt; then echo another failure; fi

(you can put a compound command inside a &&-list)


We could even have the alias make the line a comment:

#!/bin/bash
unalias -a
shopt -s expand_aliases
alias risky='#'
if [ "$1" = risky ]; then
        alias risky=''
fi
risky echo something risky, again || echo "does it fail now?"

but then of course it'll just ignore the first line, so this would again run the second line in "safe" mode:

risky echo something even more risky ||
    echo "_now_ does it fail?"

Not the answer you're looking for? Browse other questions tagged .