Some xbindkeys bindings don't work via .xprofile, requires manual process restart - linux

All of my .xbindkeysrc bindings work when I explicity run xbindkeys; however, when I put the same command in my .xprofile to be called by my display manager, LightDM, certain bindings fail. The bindings that fail to work on start-up use the playerctl command. All of my other bindings work (the others call pactl ...).
# Next song
"playerctl --player spotify next"
Mod2 + F8
If I kill the broken xbindkeys process that began on startup and re-run xbindkeys, all of the bindings work.
Any suggestions? Maybe, where could I run xbindkeys at a later point in the start-up process?

Most likely playerctl isn't in your system path. Depending on how xbindkeys is started its path may only be something like:
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
As a result it won't find the command and nothing happens when you press the key combination in question.
On Debian xbindkeys is started by the /usr/bin/xbindkeys_autostart script. For debugging it may help to temporarily modify that script a little, for example as follows:
## -22,6 +22,11 ##
# Run $PROG - if it has been configured
if [ -n "${CONF}" ]; then
- $PROG -f $CONF
+ echo ===== >> /tmp/xbk.txt
+ date >> /tmp/xbk.txt
+ cat $CONF >> /tmp/xbk.txt
+ env >> /tmp/xbk.txt
+ echo ----- >> /tmp/xbk.txt
+ $PROG -f $CONF -v 2>&1 >> /tmp/xbk.txt
fi
fi
(If you modify that script keep in mind that output to the log file is buffered, so you may have to create enough output by hitting your key bindings for the system to flush the file, or use something like unbuffer.)

Related

How to detect when a bash script is triggered from keybinding

Background
I have a Bash script that requires user input. It can be run by calling it in a terminal or by pressing a keyboard shortcut registered in the i3 (or Sway) config file as follows:
bindsym --release $mod+Shift+t exec /usr/local/bin/myscript
The Problem
I know I can use read -p to prompt in a terminal, but that obviously won't work when the script is triggered through the keybinding. In that case I can use something like Yad to create a GUI, but I'm unable to detect when it's not "in a terminal". Essentially I want to be able to do something like this:
if [ $isInTerminal ]; then
read -rp "Enter your username: " username
else
username=$(yad --entry --text "Enter your username:")
fi
How can I (automatically) check if my script was called from the keybinding, or is running in a terminal? Ideally this should be without user-specified command-line arguments. Others may use the script and as such, I'd like to avoid introducing any possibility of user error via "forgotten flags".
Attempted "Solution"
This question suggests checking if stdout is going to a terminal, so I created this test script:
#!/usr/bin/env bash
rm -f /tmp/detect.log
logpass() {
echo "$1 IS opened on a terminal" >> /tmp/detect.log
}
logfail() {
echo "$1 IS NOT opened on a terminal" >> /tmp/detect.log
}
if [ -t 0 ]; then logpass stdin; else logfail stdin; fi
if [ -t 1 ]; then logpass stdout; else logfail stdout; fi
if [ -t 2 ]; then logpass stderr; else logfail stderr; fi
However, this doesn't solve my problem. Regardless of whether I run ./detect.sh in a terminal or trigger it via keybind, output is always the same:
$ cat /tmp/detect.log
stdin IS opened on a terminal
stdout IS opened on a terminal
stderr IS opened on a terminal
It seems like the easiest way to solve your actual problem would be to change the i3 bind to
bindsym --release $mod+Shift+t exec /usr/local/bin/myscript fromI3
and do
if [[ -n "$1" ]]; then
echo "this was from a keybind"
else
echo "this wasn't from a keybind"
fi
in your script.
False Positive
As most results on Google would suggest, you could use tty which would normally return "not a tty" when it's not running in a terminal. However, this seems to differ with scripts called via bindsym exec in i3/Sway:
/dev/tty1 # From a keybind
/dev/pts/6 # In a terminal
/dev/tty2 # In a console
While tty | grep pts would go part way to answering the question, it is unable to distinguish between running in a console vs from a keybinding which you won't want if you're trying to show a GUI.
"Sort of" Solution
Triggering via keybinding seems to always have systemd as the parent process. With that in mind, something like this could work:
{
[ "$PPID" = "1" ] && echo "keybind" || echo "terminal"
} > /tmp/detect.log
It is likely a safe assumption that the systemd process will always have 1 as its PID, but there's no guarantee that every system using i3 will also be using systemd so this is probably best avoided.
Better Solution
A more robust way would be using ps. According to PROCESS STATE CODES in the man page:
For BSD formats and when the stat keyword is used, additional characters may be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+ is in the foreground process group
The key here is + on the last line. To check that in a terminal you can call ps -Sp <PID> which will have a STAT value of Ss when running "interactively", or S+ if it's triggered via keybinding.
Since you only need the STATE column, you can further clean that up with -o stat= which will also remove the headers, then pipe through grep to give you the following:
is_interactive() {
ps -o stat= -p $$ | grep -q '+'
}
if is_interactive; then
read -rp "Enter your username: " username
else
username=$(yad --entry --text "Enter your username:")
fi
This will work not only in a terminal emulator and via an i3/Sway keybinding, but even in a raw console window, making it a much more reliable option than tty above.

Is it possible to auto reboot for 5 loops through mint?

I am currently using the following command to run reboot
sudo shutdown -r now
however, I would need to run it for 5 loops before and after executing some other programs. Was wondering if it is possible to do it in MINT environment?
First a disclaimer: I haven't tried this because I don't want to reboot my machine right now...
Anyway, the idea is to make a script that can track it's iteration progress to a file as #david-c-rankin suggested. This bash script could look like this (I did test this):
#!/bin/sh
ITERATIONS="5"
TRACKING_FILE="/path/to/bootloop.txt"
touch "$TRACKING_FILE"
N=$(cat "$TRACKING_FILE" | wc -c)
if [ "$N" -lt "$ITERATIONS" ]; then
printf "." >> "$TRACKING_FILE"
echo "rebooting (iteration $N)"
# TODO: this is where you put the reboot command
# and anything you want to run before rebooting each time
else
rm "$TRACKING_FILE"
# TODO: other commands to resume anything required
fi
Then add a call to this script somewhere where it will be run on boot. eg. cron (#reboot) or systemd. Don't forget to remove it from a startup/boot command when you're finished or next time you reboot, it will reboot N times.
Not sure exactly how you are planning on using it, but the general workflow would look like:
save script to /path/to/reboot_five_times.sh
add script to run on boot (cron, etc.)
do stuff (manually or in a script)
call the script
computer reboots 5 times
anything in the second TODO section of the script is then run
go back to step 3, or if finished remove from cron/systemd so it won't reboot when you don't want it to.
First create a text document wherever you want,I created one on Desktop,
Then use this file as a physical counter and write a daemon file to run things at startup
For example:
#!/bin/sh
var=$(cat a.txt)
echo "$var"
if [ "$var" != 5 ]
then
var=$((var+1))
echo "$var" > a.txt
echo "restart here"
sudo shutdown -r now
else
echo "stop restart"
echo 0 > a.txt
fi
Hope this helps
I found a way to create a file at startup for my reboot script. I incorporated it with the answers provided by swalladge and also shubh. Thank you so much!
#!/bin/bash
#testing making a startup application
echo "
[Desktop Entry]
Type=Application
Exec=notify-send success
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_CA]=This is a Test
Name=This is a Test
Comment[en_CA]=
Comment=" > ~/.config/autostart/test.desktop
I create a /etc/rc.local file to execute user3089519's script, and this works for my case. (And for bootloop.txt, I put it here: /usr/local/share/bootloop.txt )
First: sudo nano /etc/rc.local
Then edit this:
#!/bin/bash
#TODO: things you want to execute when system boot.
/path/to/reboot_five_times.sh
exit 0
Then it works.
Don't forget edit /etc/rc.local and remove /path/to/reboot_five_times.sh when you done reboot cycling.

Why this Debian-Linux autostart netcat script won't autostart?

I placed a link to my scripts in the rc.local to autostart it on linux debian boot. It starts and then stops at the while loop. It's a netcat script that listens permantently on port 4001.
echo "Start"
while read -r line
do
#some stuff to do
done < <(nc -l -p 4001)
When I start this script as root with command ./myscript it works 100% correctly. Need nc (netcat) root level access or something else?
EDIT:
rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
/etc/samba/SQLScripts
exit 0
rc.local starts my script "SQLScripts"
SQLScripts
#! /bin/sh
# The following part always gets executed.
echo "Starting SQL Scripts" >> /var/log/SQLScriptsStart
/etc/samba/PLCCheck >> /var/log/PLCCheck &
"SQLScripts" starts "PLCCheck" (for example only one)
PLCCheck
#!/bin/bash
echo "before SLEEP" >> /var/log/PLCCheck
sleep 5
echo "after SLEEP" >> /var/log/PLCCheck
echo "vor While" >> /var/log/PLCCheck
while read -r line
do
echo "in While" >> /var/log/PLCCheck
done < <(netcat -u -l -p 6001)
In an rc script you have root level access by default. What does "it stops at the while loop" mean? It quits after a while, or so? I guess you need to run your loop in the background in order to achieve functionality usual in autostart scripts:
echo "Starting"
( while read -r line
do
#some stuff to do
done << (nc -l -p 4001) ) &
echo "Started with pid $( jobs -p )"
I have tested yersterday approximatly the same things, and I have discover that you can bypass the system and execute your netcat script with the following crontask. :
(every minute, but you can ajust that as you want.)
* * * * * /home/kali/script-netcat.sh // working for me
#reboot /home/kali/script-netcat.sh // this is blocked by the system.
According to me, I think that by default debian (and maybe others linux distrib) block every script that try to execute a netcat command.

Showing Progress in Oracle DB Silent Installation with Response File

I am running a script to install Oracle DB 11g with silent option and response file.
I noticed the shell after executing the command
$ /directory_path/runInstaller -silent -responseFile responsefilename
The install session just closes just giving me a log file location.
The installation process is active in the background. But for me no way to no about the progress and what is going on... till the prompt to run root scripts come. What if I close the putty windows etc?
Any way to keep the installer session active till finished ? and show some sort of progress on-screen ?
Any way to keep the installer session active till finished ?
Yes, you can wait for oracle silent install to finish on linux eg in a shell script as follows.
(Below was with oracle 11g release 2 for Redhat Enterprise Linux.)
You can wait for it to finish by doing:
$ /directory_path/runInstaller -silent -responseFile responsefilename |
while read l ;
do
echo "$l" ;
done
(this relies on the fact that even though the java universal installer runs in the background it keeps using stdout, so "read l" keeps succeeding until the background universal installer process exits)
and show some sort of progress on-screen ?
A bit more tricky but we can do it by figuring out the name of the logfile from the output of runInstaller before it exits. The output contains a line like:
Preparing to launch Oracle Universal Installer from /tmp/xxxxOraInstallTTT. ...
... where the TTT is a timestamp which leads us to the correct log file, /opt/oraInventory/logs/installActionsTTT.log.
Something like (I have not tested this because in my install I do not need progress output):
$ /directory_path/runInstaller -silent -responseFile responsefilename |
(
while read l ;
do
echo "$l" &&
if expr "$l" : "Preparing to launch Oracle Universal Installer from " >/dev/null
then
t=$(expr "$1" : ".*OraInstall\([^.]*\)") &&
log="/opt/oraInventory/logs/installActions${t}.log" &&
tail -f "$log" &
tpid=$!
fi
done
if [ -n "$tpid" ]
then
kill $tpid
fi
#[1]
)
... we can also tell if the install succeeded, because the universal installer always puts its exit status into the log via the two lines:
INFO: Exit Status is 0
INFO: Shutdown Oracle Database 11g Release 2 Installer
... so by adding to the above at #[1] ...
exitStatus=$(expr $(grep -B1 "$log" | head -1) : "INFO: Exit Status is\(.*\)") &&
exit $exitStatus
... the above "script" will exit with 0 status only if the oracle instal completes successfully.
(Note that including the space in the status captured by expr just above is deliberate, because bizarrely expr exits with status 1 if the matched substring is literally "0")
It is astounding that oracle would go to so much trouble to "background" the universal installer on linux/unix because:
it is trivial for the customer to generically run a script in the background:
runInstaller x y z &
... or...
setsid runInstaller x y z
it is very difficult (as we can see above) to wait for a "buried" background process to finish, and it cannot be done generically
Oracle would have saved themselves and everyone else lots of effort by just running the universal installer syncronously from runInstaller/.oui.
One useful option I found is -waitforcompletion and -nowait for windows. setup.exe will wait for completion instead of
spawning the java engine and exiting.
But still trying to figure out a way to tail that log file automatically when running the runInstaller.
UPDATE: Finally this is the only solution that worked for me.
LOGFILE=$(echo /path/oraInventory/logs/$(ls -t /path/oraInventory/logs | head -n 1))
./runInstaller -silent -responseFile /path/db.rsp -ignorePrereq
grep -q 'INFO: Shutdown Oracle Database' $LOGFILE
while [[ $? -ne 0 ]] ; do
tail -1 $LOGFILE
grep -q 'INFO: Shutdown Oracle Database' $LOGFILE
done
Instead of tailing the latest log in oraInventory, kept the process active till the last message is written to the log file. Old school but works.
It's been a while since I did an installation, but I don't think you can make it stay in the foreground; it just launches the JVM and that doesn't (AFAIK) produce any console output until the end, and you see that anyway, so it wouldn't help you much.
You should have plenty to look at though, in the logs directory under your oraInventory directory, which is identified in the oraInst.loc file you either created for the installation or already had, and might have specified on the command line. You mentioned it told you where the log file is when it started, so that would seem a good place to start. The installActions log in that directory will give you more detail than you probably want.
If you do close the terminal, the silentInstall and oraInstall logs tell you when the root scripts need to be run, and the latter even gives you the progress as a percentage - though I'm not sure how reliable that is.
Tailing the oraInstall or installActions files is probably the only way you can show some sort of progress on screen. 'Silent' works both ways, I suppose.
You probably want to "tail" the most up to date logs(ls -t would give that) generated under /tmp/OraInstallXXX directory.

Linux Ubuntu: Script works in terminal, but not .sh

Issue Summary: My script works as it should when typed into the terminal, however, it does not work correctly when executed in terminal from a .sh file, why is this?
Script:
echo World of Clucky - Frisnuk "\033]0;Frisnuk - World of Clucky\a"
#! /usr/bin/env bash
BINDIR="$(dirname "$(readlink -fn "$0")")"
cd "$BINDIR"
while true
do
source /home/clucky/MinecraftServers/Frisnuk/serverconfig/config.sh
#Start Server
java -Xms2000M -Xmx2000M -jar $serverjar.jar nogui
if [ "`date +%w%H`" = "001" ]
then
#Delete map files for The End
rm -R /Frisnuk_the_end
echo "End has been successfully reloaded"
echo "[`date +%D\ %T`] End Reloaded" >> /home/clucky/MinecraftServers/Frisnuk/EndRestart.txt
#Change Item of The Week
weekofyear=`date +%y\-%U`
s=$(<serverconfig/ItemofTheWeek/item$weekofyear.txt)
set -- $s
itemoftheweekid=$2
itemoftheweekprice=$3
xmlstarlet edit -L -u "/scs-shop/itemStack[#type='double']" -v $itemoftheweekid /plugins/ShowCaseStandalone/ffs-storage/ffss_cac8480951254352116d5255e795006252d404d8
xmlstarlet edit -L -u "/scs-shop/price[#type='double']" -v $itemoftheweekprice /plugins/ShowCaseStandalone/ffs-storage/ffss_cac8480951254352116d5255e795006252d404d8
fi
echo "If you want to stop the restart and shut the server off instead, please press Ctrl+C at this time"
for i in 5 4 3 2 1
do
echo "$i..."
sleep 1
done
echo "Restarting Server"
clear
done
Instead of working and running the server, it just says this:
World of Clucky - Frisnuk
/home/clucky/MinecraftServers/Frisnuk/craftminecraft.sh: 7: /home/clucky/MinecraftServers/Frisnuk/craftminecraft.sh: source: not found
Error: Unable to access jarfile .jar
If you want to stop the restart and shut the server off instead, please press Ctrl+C at this time
5...
4...
3...
2...
1...
I am going to take a shower shortly, but I will be returning either later tonight, or tomorrow morning. Thank you in advanced for your assistance.
You put an echo before the shebang, so your script is being interpreted by dash, not bash.
dash doesn't include source, because it's not standard.
Correct your shebang and it'll do the trick.
The standard way to source a script is executing it with ..
Instead of source ./myScript.sh, you do . ./myScript.sh. They're the same in bash.

Resources