I have a script like this:
HI="if [[ $(ioreg -r -k AppleClamshellState | grep '"AppleClamshellState"' | cut -f2 -d"=") = ' Yes' ]]; then ./lockscreen; fi"
while true; do $HI; sleep 1; done
Running bash ./test gives if: command not found. Replacing the outer double quotes with single quotes and the inner single quotes with '\'' also has the same problem.
Setting HI to echo Hello or rm -rf *.mp4 works fine.
Setting HI='if [ "" = "" ]; then echo Hi; fi' similarly fails.
It seems that because of the quotes, it assumes if is the command name, and everything else after it is an argument. I need a way to expand it out.
The point of this is that I want to make a function Loop that takes a string as an argument, and will execute that string every 10 seconds.
CodePudding user response:
Creating the loop function is straightforward. Calling it is the tricky part.
Here "$@" is the expansion of the arguments passed to loop. It's the same as writing "$1" "$2" "$3" ... for however many arguments there actually are:
loop() {
while true; do
"$@"
sleep 10
done
}
As you've experienced, variable expansion like this works fine for regular commands, but doesn't handle more complicated cases like if statements, | pipelines, && and || operators, or multi-line commands separated with ; and/or &.
The best way to support all of those features is for the caller to define a function and pass the function name to loop. Functions can use all of these features, and have the advantage of not requiring any complicated quoting or escaping:
hi() {
if [[ $(ioreg -r -k AppleClamshellState | grep '"AppleClamshellState"' | cut -f2 -d"=") = ' Yes' ]]; then
./lockscreen
fi
}
loop hi
Further reading:
CodePudding user response:
I can solve this by using do eval $HI. Of course, the problem is that if I use double quotes, then expansions are done at the first run, and if I use single quotes, it is expanded after its second run. I don't want it to be expanded, but evaluated at every run.
EDIT: I got around this by using \$, or even better, using single quotes (this did mean I had to escape all the single quotes though.
