Troubleshooting a script for my RPI to toggle displays - shell

So I have a Quimat LCD attached to my gpio.
included is a script which runs to switch to the display (LCD35-show), and another to switch back to the HDMI port (LCD-hdmi). This causes a reboot when done so any variable changes have to happen prior to this.
as this is for my mother who is afraid of touching command prompt, I am trying to set up a single icon to use to switch between video sources.
I am a novice at coding, most of my experience from dabbling in BASIC, and have spent a couple days searching and trying to set this up, but apparently am failing at how to search properly as I couldn't get it functioning.
What I have done so far is this:
Created text file state.txt to hold a variable stating what mode the device is in (HDMI or LCD)
My attempt was to read the variable, then use if then statement to determine which file to run, change the variable then run the file.
This is the code I ended up with.
!/bin/bash
read var < state.txt
if var == HDMI
then
echo LCD > state.txt
cd LCD-show/
sudo ./LCD35-show
else
echo HDMI > state.txt
cd LCD-show/
sudo ./LCD-hdmi
fi
I am hoping someone can show me what I did wrong, and hopefully explain what I missed in the process.

Be careful with your bash script comparisons.
Wrap strings in quotes (or some other method), so it's not a syntax error when string-vars evaluate to empty. You can use == for string comparisons in bash, but = works in bash and sh.
#! /bin/bash
EXE=`basename "$0"`
LCD_DIR="LCD-show"
STATE_FILE="state.txt"
if [ ! -d "$LCD_DIR" ]; then
echo "$EXE: $LCD_DIR does not exist"
exit 1
fi
read var < state.txt
if [ "$var" = "HDMI" ]; then
echo LCD > "$STATE_FILE"
cd "$LCD_DIR"
sudo ./LCD35-show
else
echo HDMI > "$STATE_FILE"
cd "$LCD_DIR"
sudo ./LCD-hdmi
fi
The difference between a good script and a great script is error handling.
What happens when the dir LCD-show does not exist? (for whatever reason).

Related

Looking for the existence of an ENV Variable

So, I'm guessing this may be a bug, or maybe I've botched something up, I dunno...
I have a script that was always working but I've been tasked to make it work using the new WSL2. I've snipped out the first block of code as it's giving me issues right off the bat. As you'll see below, I'm simply trying to determine if a variable has been set or not. This works in my Linux VM and also in Cygwin, however, it doesn't work in WSL2. Here is the code:
#!/bin/bash
echo $test_var
set -e
if [ ! -d "$test_var" ]; then
echo Please set test_var.
exit
fi
When I run this in any of the working systems I get the output of the variable.
In WSL2 I get the output of the variable followed by Please set test_var. And it stops the script due to the set -e as it's supposed to do thinking the var isn't set.
Any help would be appreciated.
Thanks
If your intention is to check if a directory exists (whose name apparently needs to be set as an environment variable in $test_var), if that directory exists relative to the current directory where the script is executed, you want something like:
#!/bin/bash
echo "$test_var"
set -e
if [ ! -d "$test_var" ]; then
echo "cannot find directory $test_var"
exit
fi
Note that here I have only changed your message, and your problem might possibly be explained by the fact that you do not have such a directory under WSL2.
If, on the other hand, you want to check if some environment variable (whatever it represents) is set, you want the -z option, something like:
#!/bin/bash
echo "$test_var"
set -e
if [ -z "$test_var" ]; then
echo "Please set test_var."
exit
fi
Note the absence of your negation sign (!).

I am looking for help trying to create a .sh file to run steam games through wines windows player

I have a computer running Ubuntu with retropie (emulationstation) which i can create .sh files to run linux based steam games through as they can be directly installed onto the computer. I have installed wine in order to play the windows based games and while I can run the files by going into windows steam and clicking play, I am looking for a way to create a .sh file that will allow me to play them through retropie. I can post some of the stuff ive tried i just am struggling with the formatting.
Let me know if i need to post anything else or fix something!
EDIT: Heres some of the code ive tried, the first i thinks should run the executable through wine but i cant get anything to output, the second is some code i found online which watches for the game to close as well so it can exit clean.
#!/bin/bash
wine ~/PlayOnLinux\'s\ virtual\ drives/Steam/drive_c/Program\
Files/Steam/steamapps/common/MortalKombat_KompleteEdition/DiscContentPC/MKKE.exe
#! /bin/bash
appid=$1
procname=$2
PREFIX=/home/rig-cade/PlayOnLinux\'s\ virtual\ drives
STEAM="/home/rig-cade/.wine-steam/drive_c/Program Files/Steam/Steam.exe"
export WINEDEBUG=-all
export WINEPREFIX=$PREFIX
if [[ ((`pgrep -f steam.exe -c` == 0)) && ((`pgrep -f Steam.exe -c` == 0)) ]]; then
optirun wine "$STEAM" -silent &
sleep 20
fi
echo "Running game"
wine "$STEAM" steam://rungameid/$appid &
sleep 15
echo "Starting checks"
status=`pgrep -f $procname -c`
if (( "$status" > 1 )); then
while (( "$status" > 1 )); do
sleep 5
status=`pgrep -f $procname -c`
done
wine "$STEAM" -shutdown &
fi
echo "Exiting"
I'm not 100% sure and I will test once I get done with work in a couple hours, but AFAIK the Steam URL protocol cannot be used with the command-line and so when you try this Steam is likely throwing a parsing error. If you add -console after -silent it should enable the Console tab and allow you to see an error message if you open the client.
Instead try one of
Only using the browser protocol without the "$STEAM" part so it's not trying to pass it as an argument to the client.
Using the Steam Command-line parameter -applaunch {appid},
where {appid} is replaced with the appid of the game to be run as you were already trying to do.

Prevent other terminals from running a script while another terminal is using it

I would like prevent other terminals from running a certain script whenever another terminal is running it however in bash but I'm not quite sure on how I would be able to go about in doing it. Any help or tip could be greatly appreciated!
In example:
When that script is being run on another terminal, all other terminals would be unable to run that certain script as well. And display a message "UNDER MAINTENANCE".
You can use the concept of a "lockfile." For example:
if [ -f ~/.mylock ]; then
echo "UNDER MAINTENANCE"
exit 1
fi
touch ~/.mylock
# ... the rest of your code
rm ~/.mylock
To get fancier/safer, you can "trap" the EXIT signal to remove it automatically at the end:
trap 'rm ~/.mylock' EXIT
Use flock and put this on top of your script:
if ! flock -xn /path/to/lockfile ; then
echo "script is already running."
echo "Aborting."
exit 1
fi
Note: path/to/lockfile could be the path to your script. Doing so would avoid to create an extra file.
To avoid race conditions, you could use flock(1) along with a
lock file. There is one flock(1) implementation
which claims to work on Linux, BSD, and OS X. I haven't seen one
explicitly for Unix.
There is some interesting discussion here.
UPDATE:
I found a really clever way from Randal L. Schwartz here. I really like this one. It relies on having flock(1) and bash, and it uses the script itself as its own lockfile. Check this out:
/usr/local/bin/onlyOne is a script to obtain the lock
#!/bin/bash
exec 200< $0
if ! flock -n 200; then
echo "there can be only one"
exit 1
fi
Then myscript uses onlyOne to obtain the lock (or not):
#!/bin/bash
source /usr/local/bin/onlyOne
# The real work goes here.
echo "${BASHPID} working"
sleep 120

Correct script construct to monitor RaspPi sound card output and execute CEC command to activate AV receiver?

Apologies in advance - I'm a complete beginner so the code below is probably a car crash but I'd really appreciate any help if anyone can spare a minute?
Aim - I have my RaspPi as a music source to my AV receiver. I've installed libcec onto RPi and the receiver is cec enabled so I am trying to write a script that sends the 'active source' command to the AVR whenever the sound card is active.
The active source command:
echo 'as' | cec-client -d 1 -s
The script to return sound card status:
grep RUNNING /proc/asound/card*/pcm*/sub*/status
I've tried to represent the following logic:
1. If music is playing - send active command (turns on AVR with correct channel) and create the empty file 'yamaha-yes'
2. If yamaha-yes file exists check that music is playing - if not then remove 'yamaha-yes' file.
The idea with the yamaha-yes file is to prevent the script from continually sending the active source command whilst music is playing - it just needs sending once, so I've tried to write it so that the presence of the file whilst music playing leads to no further action.
I was hoping to use the 'watch' command from boot to have this running continually.
#!/bin/bash
musicon="$( grep RUNNING /proc/asound/card*/pcm*/sub*/status )"
file="/etc/yamaha-yes"
if [ -e $file ] ; then
if [ "$musicon" = "" ] ; then
sudo rm /etc/yamaha-yes
fi
else
if [ "$musicon" ] ; then
echo 'as' | cec-client -d 1 -s
sudo touch /etc/yamaha-yes
fi
fi
The current error returned is 'line 8: [: too many arguments'. But I suspect there is a lot more wrong with it than that and was hoping to check I was on the right track before flogging it any further!
Thanks in advance! Tom
EDIT
Some changes made in line with Marc's advice and the code now seems to work - though I realise it still isn't the most elegant read! Perhaps there is a better way of scripting it?
The short answer is that you are missing quotes [ "$musicon" = 'RUNNING' ]. However, there are problems with how your grepping is going to work. When audio is running you could end up with multiple RUNNING values (giving the string RUNNING\nRUNNING or longer) returned which will not equal RUNNING. Also, $musicoff is broken because the ! command doesnt change a commands output, only its return value. "$musicoff" will equal RUNNING only if audio is running, which is the exact opposite of what you want. Fortunately, the fix also simplifies the script.
The behavior of grep is that it returns 0 (true) if it found the search text anywhere, otherwise it returns 1 (false). So, instead of comparing the output of grep against a specific value (which might fail in certain cases) use the return value of grep directly:
musicon="grep RUNNING /proc/asound/card*/pcm*/sub*/status"
if $musicon ; then
echo Music is on;
fi
if ! $musicon; then
echo Music is off;
fi

Simple if statement in bash doesn't work

I am learning a little bit of bash in Linux and I just can't understand why this doesn't work. It is a simple IF statement and a read command to keep the window opened. What happens is that when I execute the .sh file the terminal's window opens for a second and closes back. I can't see any message or check whether there's any error or why it doesn't work. If I remove the IF block then I can see the message and the window remains opened. This is the code inside my file
count=99
if [ $count -eq 100 ]; then
echo "Count is 100"
else
echo "Count is not 100"
fi
read -p "Press enter to continue" nothing
I tried many other ways of using the IF structure but seems like none works
Use the dos2unix utility to convert the text file created on Windows to the correct format for Linux. See this wikipedia page for more details.
Install if necessary:
$ sudo apt-get install dos2unix
<snip>
Setting up dos2unix (5.3.1-1) ...
$
Run it on your script:
$ dos2unix if.sh
dos2unix: converting file if.sh to Unix format ...
$
Your script is completely correct. atleast its okai in my linux mint

Resources