How to start up xmonad with apps on other workspaces - haskell

I'm trying to write an xmonad.hs which, at startup, launches some apps on some workspaces. Several of these apps (e.g., atop) will run within a terminal (urxvt being my preference).
This has been asked a few times before, e.g, here, here, and is obliquely touched on on the XMonad FAQ.
However, these rely on:
using spawnOn from XMonad.Actions.SpawnOn, which flat doesn't work (testing with urxvt, and also xclock as a simple example); it gets sent to the current workspace.
using spawn prog >> windows $ greedyView <workspace>, which kinda works, but has major timing issues - e.g., if you run two in succession, with different workspaces, both progs end up on the latter workspace. FWIW, I experimented with using threaddelay to assist; it didn't make any discernable difference, even with a 10s delay between spawns (I remembered that threadDelay is in microseconds, and so used 10000000).
rely on using general hooks for programs - meaning that whenever I start them up, they'll get sent to the given workspace. That's not what I want; I just want them placed there at startup.
Relatedly, it surprises me that the API doesn't let me start up an app and then give me a reference to that app/window (potentially with a timeout); so that I can confidently send that app/window to a workspace.
Any help would be greatly appreciated.

Install wmctrl
sudo apt install wmctrl
And create a script (in this example thunderbird on the second workspace (-t 1)):
#!/bin/sh
(thunderbird &) & sleep 5 &&
sh -c "wmctrl -i -r `wmctrl -l | grep Thunderbird` -t 1"
To know your application name on wmctrl you can view it by taping on your terminal :
wmctrl -l
And replace it with the correct name in the script.
Be carrefull with the capital letter ("Thunderbird" not "thunderbird") !!
Other example with firefox on the 3d workspace (-t 2):
#!/bin/sh
(firefox &) & sleep 5 &&
sh -c "wmctrl -i -r `wmctrl -l | grep Firefox` -t 2"
Bonus :
Here is the command to execute at start-up :
sh -c "thunderbird & sleep 5 && wmctrl -i -r `wmctrl -l | grep Thunderbird` -t 1"
Work on Debain 10 with Cinnamon. But should work for all

You can spawn the app via startupHook and then use a manageHook to handle window placement.
manageHook such as:
, className =? "deluge" --> doShift ( myWorkspaces !! 3 )
The above will actually spawn deluge on Workspace 4. In my startupHook I have
spawnOnce "deluge-gtk" to launch the app on start-up.
You would want to import XMonad.Util.SpawnOnce. doShift comes from the default XMonad.ManageHooks You could also take a look at XMonad.Actions.SpawnOn but I only use manageSpawn from that module.

Related

How to detect if i3-wm is being run or GNOME is being run in bash

I've been using i3-wm for about six months now, and I had to switch to GNOME because Discord was crashing a lot in i3. I had previously used the i3-msg command in my bashrc to make sure the borders of the terminal wouldn't be visible, as to use the entire screen space for the terminal. The specific command I run is:
i3-msg -q border toggle
The problem is, when I use GNOME and I open up a terminal, the i3-msg command runs, and causes an error message evidently caused by the fact that i3 isn't running. The ideal scenario would be to add an if statement that checks if i3 is running, and if it is, then run the i3-msg command.
My question: What is the most convenient way to determine which window manager / Desktop Environment is currently running in my system?
When i3 is active, there should be a proces called "i3". You could check that with pgrep.
if pgrep -x "i3" > /dev/null
then
echo "i3 is running"
fi
-x is short for --exact – without it the if clause would still work, as long as no non-i3 process' name contains i3.
Omitting > /dev/null would print out the pid(s) found by pgrep.
Instead of pgrep you could also use pidof or ps -C. Instead of idiomatic if-then-fi you could also just use && like pidof i3 > /dev/null && echo "i3 is running" || echo "i3 is not running"

Script runs fully when ran manually but misses commands when ran from another script

I have 2 scripts that I'm testing to automate starting services on my server however they behave weirdly.
The first script is
#!/bin/sh
screen -dmS Test_Screen
sleep 1
sudo sh cd.sh
echo "finished"
Which runs perfectly however the script it runs does not and is as follows
#!/bin/sh
screen -S Test_Screen -X stuff "cd /home/Test"
sleep 1
screen -S Test_Screen -X eval "stuff \015"
sleep 1
echo "Complete"
The second script will run perfect if I run it from command line and will CD into the directory within the screen. However, if it runs from the first script it Will Not CD into the correct directory within the screen, but it will still print "Complete".
I'm Using CENTOS 6.7 and the latest version of GNU screen
Any Ideas?
This seems to be a problem with session nesting.
In your first script you create a session named Test_Screen.
In your second script the -S parameter tells screen to create a session of the same name. This might cause screen to exit and not cd into the correct directory.
You could move the cd command in front of the sudo sh cd.sh and remove those screen calls from the second script leaving only
stuff \015
echo "Complete"
Using the correct screenflags should also work.
#!/bin/sh
screen -dr Test_Screen -X stuff "cd /home/Test"
sleep 1
screen -dr Test_Screen -X eval "stuff \015"
sleep 1
echo "Complete"
For a more modern alternative to screen, have a look at tmux.
Ok so this turned out really weird. After posting i tried a couple of things on a centos 6.7 hyper V test environment and got the exact same issue. However, later in the day we ended up changing service provider and upgrading to centos 7 in the process. I am not sure why but since the update the script now runs perfectly and i was able to actually merge the two scripts into one in order to make it more efficient. If anyone knows why the update fixed it feel free to let me know.

Open gnome-terminal from shell script and hold window open

I'm trying to write a script that sets up my programming environment by taking as an argument the name of the project(directory) I want to open
so for example: ./my_script.sh sample_app
And here is the script so far:
#!/bin/bash
wmctrl -s 0
sublime &
sleep 2
wmctrl -s 1
google-chrome &
sleep 2
wmctrl -s 2
Dir="$echo /home/biTNumb/Projects/ruby/workspace/$1"
echo $Dir
gnome-terminal --window-with-profile=Guard -e ls &
#gnome-terminal -e cd /home/biTNumb/Projects/ruby/workspace/$1 && bundle exec guard &
#gnome-terminal -e cd /home/biTNumb/Projects/ruby/workspace/$1 && rails s &
The problem arises when the script executes:
gnome-terminal --window-with-profile=Guard -e ls &
I get the message The child process exited normally with status 0.:
I can't use the terminal after (I can only close it) and the message hides some part of the output. And yet, I have already created a profile and set the When command exits dropdown menu to 'Hold the terminal open'...
** I left the comments in the script so you can get the idea of what I'm trying to do
To execute multiple commands in the same gnome-terminal window, use semicolons ; as separators like below:
gnome-terminal -- bash -c "command 1; command 2; ...; bash;"
The last command bash starts the command-line interpreter so that the terminal doesn't exit at the end (use $shell instead of bash for a more general solution).
This way you won't need to define a profile with the option Hold the terminal open when command exits and you won't get the message The child process exited with status 0 (which hide some parts of the output).
Here is what you might write (I use backslashes \ to split lines):
gnome-terminal -- bash -c \
" ls ;\
cd /home/biTNumb/Projects/ruby/workspace/$1 && bundle exec guard ;\
cd /home/biTNumb/Projects/ruby/workspace/$1 && rails s;\
$bash;"

How to run a script in background (linux openwrt)?

I have this script:
#!/bin/sh
while [ true ] ; do
urlfile=$( ls /root/wget/wget-download-link.txt | head -n 1 )
dir=$( cat /root/wget/wget-dir.txt )
if [ "$urlfile" = "" ] ; then
sleep 30
continue
fi
url=$( head -n 1 $urlfile )
if [ "$url" = "" ] ; then
mv $urlfile $urlfile.invalid
continue
fi
mv $urlfile $urlfile.busy
wget -b $url -P $dir -o /www/wget.log -c -t 100 -nc
mv $urlfile.busy $urlfile.done
done
The script basically checks for any new URLs at wget-download-link.txt for every 30 seconds and if there's a new URL it'll download it with wget, the problem is that when I try to run this script on Putty like this
/root/wget/wget_download.sh --daemon
it's still running in the foreground, I still can see the terminal output. How do I make it run in the background ?
In OpenWRT there is neither nohup nor screen available by default, so a solution with only builtin commands would be to start a subshell with brackets and put that one in the background with &:
(/root/wget/wget_download.sh >/dev/null 2>&1 )&
you can test this structure easily on your desktop for example with
(notify-send one && sleep 15 && notify-send two)&
... and then close your console before those 15 seconds are over, you will see the commands in the brackets continue execution after closing the console.
The following command will also work:
((/root/wget/wget_download.sh)&)&
This way you don't have to install the 'nohub' command in the tight memory space of the router used for OpenWrt.
I found this somewhere several years ago. It works.
The &at the end of script should be enough, if you see output from the script it means, that stdout and/or stderr is not closed, or not redirect to /dev/null
You can use this answer:
How to redirect all output to /dev/null
I am using openwrt merlin and the only way to get it working was using the crud cron manager[1]. Nohub and screen are not available as solutions.
cru a pinggw "0 * * * * /bin/ping -c 10 -q 192.168.2.254"
works like charm
[1][https://www.cyberciti.biz/faq/how-to-add-cron-job-on-asuswrt-merlin-wifi-router/]
https://openwrt.org/packages/pkgdata/coreutils-nohup
opkg update
opkg install coreutils-nohup
nohup yourscript.sh &
You can use nohup.
nohup yourscript.sh
or
nohup yourscript.sh &
Your script will keep running even if you close your putty session, and all the output will be written to a text file in same directory.
nohup is often used in combination with the nice command to run processes on a lower priority.
nohup nice yourscript.sh &
See: http://en.wikipedia.org/wiki/Nohup
For busybox in Openwrt Merlin system, I got a better solution which combined cru and date command
cru a YOUR_UNIQUE_CRON_NAME "`date -D '%s' +'%M %H %d %m *' -d $(( \`date +%s\`+2*60 ))` YOUR_CMD_HERE"
which add a cron job running 2 minutes later, and only run once.
Inspired by PlagTag's idea.
In another way these code would tried:
ssh admin#192.168.1.1 "/jffs/your_script.sh &"
Simple and without any programs like nohup screen...
(BTW: worked on Asus-Merlin firmware)
Try this:
nohup /root/wget/wget_download.sh >/dev/null 2>&1 &
It will go to the background so when you close your Putty session, it will be still running, and it won't send messages to the terminal.

Server Startup Script Problems

I am trying to set up a Minecraft server. However, the basic startup scripts provided do not fit my needs. I want a script that will:
Start a new screen running the jarfile and (pretty much) only the jarfile (so i can ^C it if needed without killing other things like screen or my gzip commands)
Gzip any logs that weren't gzipped automatically by the jarfile (for if/when i ^C'ed the server, or if it crashed)
Run a command with sudo to set the process in the first argument to a high priority (/usr/bin/oom-priority)
Run a http-server on the resource-pack directory in a different screen and send ^C to it when the server closes
I have these three commands. I run startserver to start the server.
startserver:
#!/bin/bash
set -m
cd /home/minecraftuser/server/
echo
screen -dm -S http-server http-server ./resource-pack
screen -dm -S my-mc-server startserver_command
(sleep 1; startserver_after) &
screen -S my-mc-server
startserver_command:
#!/bin/bash
set -m
cd /home/minecraftuser/server/
echo
java -Xmx768M -Xms768M -jar ./craftbukkit.jar $# &
env MC_PID=$! > /dev/null
(sleep 0.5; sudo /usr/bin/oom-priority $MC_PID) &
fg 1
echo
read -n 1 -p 'Press any key to continue...'
and startserver_after:
#!/bin/bash
cd /home/minecraftuser/server/
wait $MC_PID
find /home/minecraftuser/server/logs -type f -name "*.log" -print | while read file; do gzip $file &
done
screen -S http-server -p 0 -X stuff \^c\\r
Edit: When I run startserver, I get a command prompt then a bunch of gzip errors of files already existing (I am expecting these errors, but when I run startserver I'm supposed to get the java program). Somehow I am in a screen because when I do ^A d, I am brought to a new prompt.
Once I am out of the screen, screen -ls returns two instances of my-mc-server. One is a blank command prompt, the other is the server running successfully.
Edit 2: I changed startserver_command to remove the asterisk from env MC_PID=$! & (not needed there) and added it to (sleep 1; startserver_after) (makes it faster), redirected env line to /dev/null (removes entire environment listing at beginning of output). Still didn't fix the entire problem.
Instead of starting each screen session from the scripts, you can just use a custom .screenrc to specify some startup windows (and to run commands/scripts):
#$HOME/mc-server.screenrc
screen -t http-server 0 'startserver'
screen -t my-mc-server 1 'startserver_command'
screen -t gzip-logs 2 'startserver_after'
Then simply start screen (specifying the config file to use, if it's not the default ~/.screenrc)
screen -dm -c mc-server.screenrc

Resources