Paweł Glica
Paweł Glica

Reputation: 100

bash execute variable (with command that held variable which is created inside if statement )

Hi i have script as below:

mode= loop1 or loop2
command1="screen -dm -S $name feh *.jpg"

if [ "$(screen -S loop1 -X select . ; echo $?)" != 0 ] && [[ $mode != "loop1" ]];then 
name="loop1"
eval "$command1"
elif [ "$(screen -S loop2 -X select . ; echo $?)" != 0 ] && [[ $mode != "loop2" ]] ;then
name="loop2"
eval "$command1"
else 
echo "error"
fi

Basically it check if there is screen session named loop1 or loop2 if there is not, it evaluate variable $command1 which inside have another variable $name which should have change when the bash get inside loop. the problem is that variable $command1 is initialized globally before if statement start and in that time there is no variable $date.

When loop evaluate $command1 it do not use variable $name setted line before in loop statement.

I need pass to the variable command1 value of variable name

Do you have any clue ?

Upvotes: 0

Views: 135

Answers (3)

Etan Reisner
Etan Reisner

Reputation: 81022

While chepner is entirely correct that you are going to run into Bash FAQ 050 problems and you shouldn't try to do that.

The more immediate problem here is an evaluation order issue.

When the shell runs this line command1="screen -dm -S $name feh *.jpg" it is expanding $name at that point (which, as you'll notice, is before you've assigned the name variable a value).

Switching the order of those (groups of) lines would work for this issue but wouldn't do anything for the other Bash FAQ 050 issues.

Additionally, [ "$(screen -S loop1 -X select . ; echo $?)" != 0 ] is an inefficient and unnecessary way to test a command for a successful return code.

[ is a command (also known as test). It isn't an integral part of the syntax of an if statement.

The syntax of an if statement in the shell is if <command>; then ... fi where <command> can be anything that returns a return code appropriately. [ just happens to be a commonly used command in that space.

But if your command (screen -S loop1 -X select . in this case) already returns success/failure appropriately then you can avoid [ entirely and just use your command.

if ! screen -S loop1 -X select . && [[ $mode != "loop1" ]];then 
    name="loop1"
elif ! screen -S loop2 -X select . && [[ $mode != "loop2" ]] ;then
    name="loop2"
else 
    echo "error"
fi

Upvotes: 1

tripleee
tripleee

Reputation: 189789

As already pointed out in a comment, this is a FAQ: http://mywiki.wooledge.org/BashFAQ/050

A sensible workaround is to refactor the command into a parametrized function. The conditionals should also be cleared up of pretzel logic -- printing a command's exit code and comparing it to the string zero is a clumsy way to reimplement the basic functionality of the built-in if conditional!

mode=loop1 # or loop2
run_feh (} {
    screen -dm -S "$1" feh *.jpg
}

no_screen_of_loop () {
    ! screen -S "$1" -X select . && [[ "$2" != "$1" ]]
}

if no_screen_of_loop "loop1" "$mode"; then
    run_feh "loop1"
elif no_screen_of_loop "loop2" "$mode"; then
    run_feh "loop2"
else 
    echo "error" >&2    # note stderr
fi

If having a value in $name after the conditional is necessary, a slight additional refactoring will be necessary.

Upvotes: 2

Paweł Pajchrowski
Paweł Pajchrowski

Reputation: 1

It should work:

mode= loop1 or loop2
command1="screen -dm -S name feh *.jpg"

if [ "$(screen -S loop1 -X select . ; echo $?)" != 0 ] && [[ $mode !=     "loop1" ]];then 
eval "${command1/name/loop1}"
elif [ "$(screen -S loop2 -X select . ; echo $?)" != 0 ] && [[ $mode !=     "loop2" ]] ;then
eval "${command1/name/loop2}"
else 
echo "error"
fi

Upvotes: 0

Related Questions