Open gnome terminal programmatically and execute commands after bashrc was executed - bash

I try to build a little script to start my development environment. For that task I try to open a gnome terminal with several tabs where automatically the rails server and autotest is started.
But
gnome-terminal --tab -e "rails server" --tab --tab
does not work ("error creating the child process").
Also
gnome-terminal --tab -e "bash -c \"rails server\"" --tab --tab`
does not work.
Any suggestions how to solve that problem?

Here is a nice trick we worked out at Superuser
Add a eval "$BASH_POST_RC" to the end of your .bashrc
Set the BASH_POST_RC environment variable for each tab to that command you like to execute, e.g.: gnome-terminal --working-directory="/home/zardoz/projects/my_rails_app" --tab -e 'bash -c "export BASH_POST_RC=\"rails server\"; exec bash"' --tab -e 'bash -c "export BASH_POST_RC=\"autotest\"; exec bash"'
#Gilles: Thanks for that solution!

Stab in the dark: create shell scripts for each command you want to run in a tab, make them executable, and invoke them by absolute path, e.g. put this in /home/zardoz/bin/railsstart
#! /bin/sh
exec rails server
chmod +x it, and then do
gnome-terminal --tab -e /home/zardoz/bin/railsstart --tab --tab ...
If that doesn't work, the next thing I would try is sticking strace -f -o /tmp/trace.log on the beginning of the command, letting it fail, and then digging through trace.log to find out which system call actually failed and why (there'll be a tremendous amount of junk in there - read from the end backward and look for all-capitalized code phrases starting with E, like "ENOEXEC", "ENOENT", "EPERM", sort of thing.)
EDIT: Here's how you pull in all the .bashrc settings in one of these scripts:
#! /bin/bash
. ~/.bashrc
exec rails server
Caution: you may need to adjust your .bashrc so that it doesn't do certain things that only work in a "real" interactive shell session. Don't worry about this unless you get strange errors before rails starts.

I'm assuming the error arises because PATH is not set at the time gnome-terminal tries to run rails.
Why not use the full path to the rails server, or create a script that sets the PATH variable?

Already replied, but just in case, check out this gem that automates the terminal on KDE, OSX and Gnome desktops.

for ubuntu 16.04
press Ctr+Shift+T
this will open a new tab in the same window. additionally a button for adding more tabs will appear next to the right most tab.

Related

How to launch WSL as if I've logged in?

I have a WSL Ubuntu distro that I've set up so that when I login 4 services start working, including a web API that I can test via Swagger to verify it is up and working.
I'm at the point where what I want to do now is start WSL via a script - that is, launch my distro, have all of the services start, and do it from Python. The problem is I cannot even figure out the correct syntax to get WSL to start from PowerShell in a manner where my services start.
Side note: "services" != systemctl (or similar) calls, but just executing bash CLI commands from either my .bashrc or .profile at login.
I've put the commands to execute in .profile & .bashrc. I've configured it both for root execution and non-root user execution. I've taken the commands out of those 2 files and put it into a script in the Windows file system that I pass in on the start of wsl. And I've put that shell script in the WSL file system as well. Nothing seems to work, and sometimes the distro starts and then stops after about 30 seconds.
Some of the PS CLI commands I've tried:
Start-Job -ScriptBlock{ wsl -d distro -u root }
Start-Job -ScriptBlock{ wsl -d distro -u root 'bash -i -l -c /root/bin/start.sh'
Start-Job -ScriptBlock{ wsl -d distro -u root 'bash -i -l -c .\start.sh'
wsl -d distro -u root -- bash -i -l -c /root/bin/start.sh
wsl -d distro -u root -- bash -i -l -c .\start.sh
wsl -d distro -u root -- /root/bin/start.sh
Permutations of the above that I've tried: replace root with my default login, and turning all of the Start-Job bash options into a comma-separated list of single-quoted strings (Ex: 'bash', '-i', '-l', ... ). Nothing I launch from the CLI will allow me access to the web API that is supposed to be hosted on my distro.
Any advice on what to try next?
Not necessarily an answer here as much as troubleshooting tips which will hopefully lead to an answer:
First, most of the forms that you are using seem to be correct. The only ones that absolutely shouldn't work are those that attempt to run the script from the Windows filesystem.
Make sure that you have a shebang line starting your script. I'm assuming you do, but other readers may come across this as well. For the moment, try this form:
#!/usr/bin/env -S bash -li
That's going to have the same effect as the bash -li you tried -- It will source both both interactive startup files such as ~/.bashrc as well as login profiles such as ~/.bash_profile (and /etc/profile.d/*, etc.).
Note that preferably, you won't need the -li. Best practice would be to move anything necessary for the services over from the startup scripts to your start.sh script, and avoid parsing the profile and rc. I need to go update some of my answers, since I just realized I've been guilty of giving some potentially bad advice ...
Specifically, though, I'm wondering if your interactive Bash config has something truly, well, "interactive" in it that might be preventing the automatic running of the script itself. Again, best practice would be for ~/.bashrc to only hold configuration that is needed for interactive shell sessions.
Make sure the script is set as executable (chmod +x start.sh). Again, I'm assuming this is the case for you.
With a shebang line and an executable script, use something like:
wsl -d distro -u root -e /root/bin/start.sh
The -e tells WSL to launch the script directly. Since it has a shebang line, it will be parsed by Bash. Most of the other forms you use above actually run Bash twice - Once when launching WSL and another when it finds the shebang line in the script.
Try some basic troubleshooting for your script like:
Add set -x to the top (right under the shebang line) to turn on script debugging.
Add a ps -efH at the end to show the processes that are running when the script completes
If needed, resort to quick-and-dirty echo statements to show where things have progressed in the script.
I'm hopeful that the above will at least show you the problem, but if not, add the debugging info that you gain from this to your question, and we can troubleshoot further.

How to fix "Failed to execute child process source (no such file or directory)"

I am trying to run a script in order to source my catkin workspace prior to running a driver.
This is the bash I am trying to run:
#!/bin/bash
gnome-terminal -e sudo systemctl start firmwared.service
sphinx /opt/parrot-sphinx/usr/share/sphinx/drones/bebop2.drone &
gnome-terminal -e source ~/bebop_ws/devel/setup.bash
roslaunch bebop_driver bebop_node.launch ip:=10.202.0.1
I get failed to execute child process source (no such file or directory) when running my bash
Seems like the problem was the quoting, it should look like this
gnome-terminal -e "bash -c 'source ~/bebop_ws/devel/setup.bash;roslaunch bebop_driver bebop_node.launch ip:=10.202.0.1'"
IF you want to use GUI on windows and failed then just use next command:
sudo apt-get install dbus-x11
source is built into the shell, so you would have to do something like
gnome-terminal -e 'bash -c "source ~/bebop_ws/devel/setup.bash"'

Sending Bash Aliases to detached screen sessions

I'm on a Linux machine using screen, and I'm attempting to write a (fairly portable) function which runs a bash function in a new, detached screen session which automatically closes upon completion. I've had some success, but I noticed the following behavior:
If I include the definition of mail_submit() in my ~/.bashrc file, I can run
mail_submit foo
in the terminal, and also I can access the alias in a new screen session:
screen -S test
mail_submit foo
However, the following command does not work:
screen -d -m -S test sh -c 'mail_submit foo'
presumably because sh -c starts a fresh shell that has no knowledge of my ~/.bashrc profile. So, I can use the following fix:
screen -d -m -S test sh -c 'source ~/.bashrc; mail_submit foo'
which does work.
But if I want to wrap this functionality up into a bash alias (which is my ultimate goal here), this will cause a weird self-referential situation.
Question: What is an easy way to either have sh -c know the location of my ~/.bashrc profile, or use a variant of sourcing the file and creating an alias?
EDIT: I could save the shell script in my home directory, and create an alias which runs
screen -d -m -S test bash -c '~/mail_submit.sh $1'
but I'd still be curious to hear other possible fixes.
A default ~/.bashrc contains this ([[ "$-" != *i* ]] && return) little piece of code on top of it (or somewhere else in the upper part). This line will prevent the ~/.bashrc from beeing sourced if the bash shell doesn't run in interactive mode.
You could:
Remove this line
Create a new file which will only contain the alias you need and source that
Create a little bash script instead of an alias and run that
Do you mean screen -d -m -S test bash -c 'mail_submit foo'?
It looks like you're trying to run the command with the shell (sh), and not the bourne again shell (bash), which is the shell interpreter which actually reads the ~/.bashrc profile.
Edit: The .bashrc file is not being sourced by default because screen does not create the bash process as a login shell, which is when the .bashrc file is read. Creating a .screenrc file with the line defshell -bash will create the bash process as a login shell instead, which will then call the .bashrc file.

sending script over ssh using ruby

I'm attempting to write a bash script in ruby that will start a Resque worker for one of my apps.
The command that I generate from the params given in the console looks like this...
command = "ssh user##{#ip} 'cd /path/to/app; bundle exec rake resque:work QUEUE=#{#queue}&'"
`command`
The command is interpolated correctly and everything looks great. I'm asked to input the password for the ssh command and then nothing happens. I'm pretty sure my syntax is correct for making an ssh connection and running a line of code within that connection. ssh user#host 'execute command'
I've done a simpler command that only runs the mac say terminal command and that worked fine
command = "ssh user##{#ip} 'say #{#queue}'"
`command`
I'm running the rake task in the background because I have used that line once inside ssh and it will only keep the worker alive if you run the process in the background.
Any thoughts? Thanks!
I figured it out.
It was an rvm thing. I need to include . .bash_profile at the beginning of the scripts I wanted to run.
So...
"ssh -f hostname '. .bash_profile && cd /path/to/app && bundle exec rake resque:work QUEUE=queue'" is what I needed to make it work.
Thanks for the help #Casper
Ssh won't exit the session until all processes that were launched by the command argument have finished. It doesn't matter if you run them in the background with &.
To get around this problem just use the -f switch:
-f Requests ssh to go to background just before command execution. This is
useful if ssh is going to ask for passwords or passphrases, but the user
wants it in the background. This implies -n. The recommended way to start
X11 programs at a remote site is with something like ssh -f host xterm.
I.e.
"ssh -f user##{#ip} '... bundle exec rake resque:work QUEUE=#{#queue}'"
EDIT
In fact looking more closely at the problem it seems ssh is just waiting for the remote side to close stdin and stdout. You can test it easily like this:
This hangs:
ssh localhost 'sleep 10 &'
This does not hang:
ssh localhost 'sleep 10 </dev/null >/dev/null &'
So I assume the last version is actually pretty closely equivalent to running with -f.

Bash script: Turn on errors?

After designing a simple shell/bash based backup script on my Ubuntu engine and making it work, I've uploaded it to my Debian server, which outputs a number of errors while executing it.
What can I do to turn on "error handling" in my Ubuntu machine to make it easier to debug?
ssh into the server
run the script by hand with either -v or -x or both
try to duplicate the user, group, and environment of the error run in your terminal window If necessary, run the program with something like "su -c 'sh -v script' otheruser
You might also want to pipe the result of the bad command, particularly if run by cron(8), into /bin/logger, perhaps something like:
sh -v -x badscript 2>&1 | /bin/logger -t badscript
and then go look at /var/log/messages.
Bash lets you turn on debugging selectively, or completely with the set command. Here is a good reference on how to debug bash scripts.
The command set -x will turn on debugging anywhere in your script. Likewise, set +x will turn it off again. This is useful if you only want to see debug output from parts of your script.
Change your shebang line to include the trace option:
#!/bin/bash -x
You can also have Bash scan the file for errors without running it:
$ bash -n scriptname

Resources