Shell script calling ''zsh -l && some_command'' never running some_command - shell

I have this basic shell script that I'm invoking via an alias:
#!/bin/sh
cd /Users/tillman/t-root/dev/apps/actual-server &&
env /usr/bin/arch -x86_64 /bin/zsh --login &&
yarn start
It moves directory, changes the arch but does not execute yarn start
If I break this up into two consecutive commands (executing the first and then the second within iterm via different aliases), it works:
alias = intel
env /usr/bin/arch -x86_64 /bin/zsh --login
alias = abudget
cd /Users/tillman/t-root/dev/apps/actual-server
yarn start
Output:
~ intel  ✔
~ abudget  ✔
yarn run v1.22.19
$ node app
Initializing Actual with user file dir: /Users/tillman/t-root/dev/apps/actual-server/user-files
Listening on 0.0.0.0:5006...
Why is it that the first option, with all commands in one script, does not work?

You need the yarn start to be run by the copy of zsh, not run after that copy of zsh exits (which is what your code does now).
Consider using a heredoc or the -c argument to pass the code you want zsh to run on zsh's stdin:
#!/bin/sh
# ''|| exit'' prevents need to use && to connect to later commands
cd /Users/tillman/t-root/dev/apps/actual-server || exit
exec /usr/bin/arch -x86_64 /bin/zsh --login -c 'exec yarn start'
The execs are a performance enhancement, replacing the original shell with zsh, and then replacing the copy of zsh with a copy of yarn, instead of fork()ing subprocesses in which to run zsh and then yarn. (This also makes sending a signal to your script deliver that signal direct to yarn).

Related

Why does terminal stop after run "bash" in a .bat file (WSL) and how to run it properly?

I would like to automatize a process running a .bat file but using the bash terminal in my WSL2. These are my commands in my .bat:
bash
cd ~/Dev/Folder
nvm use 14.15.0
npm start
But the .bat stops after running "bash". I also tried with bash && cd ~/Dev/Folder && nvm use 14.15.0 && npm start and also replacing "bash" with "wsl", but same result.
Maybe I'm doing something wrong, so I would appreciate some help with this.
bash starts a new Bash shell and waits for it to exit, like for any other terminal command. The subsequent commands are not redirected to Bash - they'll be executed once the Bash process exits.
To run commands within Bash, use the -c flag:
bash -c "cd ~/Dev/Folder && ls && nvm use 14.15.0 && npm start"
Also see What does 'bash -c' do?.

How can I use bash constructs like 'cd' or '&&' or '>' redirection with ddev exec?

I'm trying to do some complex things with bash in the container using ddev exec and can't seem to get it to work. For example, ddev exec cd /var/tmp results in a big error message
Failed to execute command [cd /var/tmp]: Failed to run docker-compose [-f /Users/rfay/workspace/d8git/.ddev/docker-compose.yaml exec -T web cd /var/tmp], err='exit status 126', stdout='OCI runtime exec failed: exec failed: container_linux.go:348: starting container process caused "exec: \"cd\": executable file not found in $PATH": unknown
And trying to use "||" and "&&" or shell redirection with ">" doesn't work either.
Edit 2019-05-14: As of today's ddev release, v1.8.0, the answer below is obsolete, as ddev exec and exec hooks are executed in bash context. So ddev exec "ls | grep php" now works, ddev exec "mysql db <somefile.sql" works, as does an exec hook like exec: mysql <somefile.sql
ddev exec (and the "exec" hook in config.yaml) both execute actual comamnds, and not in the context of the shell. "cd" is not a Linux command, but rather a shell built-in. And '&&', '||', and '>' or '>>' are also shell constructs. So we have to do a bit of workaround to make them work.
But we can use bash explicitly to get these things to work:
ddev exec bash -c "cd /var/tmp && ls > /tmp/junk.txt"
To do the same thing in a post-start hook in config.yaml:
hooks:
post-start:
- exec: bash -c "cd /var/tmp && ls > /tmp/junk.txt"
Note that environment variables will not persist between exec statements, because they're in different shells, so it's best if you need to keep context to do it in one-liners.
Note also that if you want to redirect stdout/stderr you can redirect either within the container (as above) or to the host (redirecting the ddev exec output) like this:
ddev exec bash -c "cd /var/tmp && ls" >/tmp/junk.txt
It's possible that ddev exec might in the future execute commands in the context of bash to make this more transparent.

Execute gcloud commands in a bash script

gcloud init command doesn't offer login prompt during a bash script execution.
But it offered the login after I typed exit command manually after script ended.
vagrant#vagrant-ubuntu-trusty-64:~$ exit
logout
Welcome! This command will take you through the configuration of gcloud.
Settings from your current configuration [default] are:
Your active configuration is: [default]
Pick configuration to use:
[1] Re-initialize this configuration [default] with new settings
[2] Create a new configuration
Please enter your numeric choice: 1
Your current configuration has been set to: [default]
To continue, you must log in. Would you like to log in (Y/n)?
My bash script:
#!/usr/bin/env bash
OS=`cat /proc/version`
function setupGCE() {
curl https://sdk.cloud.google.com | bash
`exec -l $SHELL`
`gcloud init --console-only`
`chown -R $USER:$USER ~/`
}
if [[ $OS == *"Ubuntu"* || $OS == *"Debian"* ]]
then
sudo apt-get -y install build-essential python-pip python-dev curl
sudo pip install apache-libcloud
setupGCE
fi
How can I get the login prompt during the bash script execution?
There are a number of issues with the posted snippet.
The correct snippet is (probably):
function setupGCE() {
curl https://sdk.cloud.google.com | bash
gcloud init --console-only
chown -R $USER:$USER ~/
}
The first error with the original, which you discovered yourself (the what of it at least it not the why), is that exec -l $SHELL is blocking progress. It does that because you've run an interactive shell that is now waiting on you for input and the function is waiting for that process to exit before continuing.
Additionally, exec replaces the current process with the spawned process. You got lucky here actually. Had you not wrapped the call to exec in single quotes your function would have exited the shell script entirely when you exited the $SHELL it launched. As it is, however, exec just replaced the sub-shell that the backticks added and so you were left with a child process that could safely exit and return you to the parent/main script.
The second issue is that backticks run the command they surround and then replace themselves with the output. This is why
echo "bar `echo foo` baz"
outputs bar foo baz, etc. (Run set -x before running that to see what commands are actually being run.) So when you write
`gcloud init --console-only`
what you are saying is "run gcloud init --console-only then take its output and replace the command with that" which will then attempt to run the output as a command itself (which is likely not what you wanted). Similarly on the other lines.
This happens to not have been problematic here though as chown and likely gcloud init don't return anything and so the resulting command line is empty.
Somehow the exec -l $SHELL did all the mess. I changed it to source ~/.bashrc and now it works.

Ubuntu start up Rails on boot up

I want to start my Rails server with the following command on boot up:
cd /home/ubuntu/app && bundle exec rails server -p 8080 -e production
I placed it inside the /etc/rc.local, but it never starts up the server. If I remove bundle exec then shell complains about not finding the rails command.
Both variants, with and without bundle exec, work if I log in, and execute it manually.
I am totally lost. Any suggestions?
Try to change a user
su ubuntu && cd /home/ubuntu/app && bundle exec rails server -p 8080 -e production
Running your script as root is not a good idea, so you want to change user before starting your code.
su is indeed the command you want to use, but you need to realise that all arguments are passed to the login shell. So the following won't work (assuming fofox is your username):
su fofox pwd
as you're effectively saying
/bin/bash /bin/pwd
but /bin/pwd does not contain a list of shell commands, so both will give an error message:
/bin/pwd: /bin/pwd: cannot execute binary file
Thus you need to add something to the shell saying you're passing a list of commands, like this:
/bin/bash -c /bin/pwd
The last wrinkle is that you want to pass a number of arguments to the su command but protect them from the shell, as
su fofox -c id && id
will show you that the first bit is executed as fofox and the second part as root again. Single quotes are used to prevent the root shell to see the && characters.
So the final command becomes:
su fofox -c 'cd /home/ubuntu/app && bundle exec rails server -p 8080 -e production'

Why does ruby script stop when trying to start unicorn_rails as daemon?

I'm trying to start unicorn_rails in a ruby script, and after executing many commands in the script, when the script gets to the following line
%x[bash -ic "bash <(. ~/.bashrc); cd /home/www-data/rails_app; bundle exec unicorn_rails -p 8000 -E production -c /home/www-data/rails_app/config/unicorn.rb -D"]
the script stops, generating the following output
[1]+ Stopped ./setup_rails.rb
and returns to the Linux prompt. If I type "fg", the script finishes running, the line where the script had stopped gets executed and unicorn gets started as a daemon.
If I run the line in a separate script, the script completes without stopping.
UPDATE_1 -
I source .bashrc because earlier in the script I install rvm and to get it to run with the correct environment I have the following:
%x[echo "[[ -s \"$HOME/.rvm/scripts/rvm\" ]] && source \"$HOME/.rvm/scripts/rvm\"" >> .bashrc]
%x[bash -ic "bash <(. ~/.bashrc); rvm install ruby-1.9.2-p290; rvm 1.9.2-p290 --default;"]
So if I want to run correct version of rvm, ruby and bundle I need to source .bashrc
end UPDATE_1
Does anyone have any idea what could cause a ruby script to halt as if control-Z was pressed?
Not sure why it's stopping, but my general rule of thumb is to never source my .bashrc in a script -- that might be the source of your problem right there, but I can't be sure without seeing what's in it. You should be able to change your script to something like:
$ vi setup_rails.sh
#!/usr/bin/bash
# EDIT from comments below
# expanding from a one liner to a better script...
$RVM_PATH=$HOME/.rvm/scripts
# install 1.9.2-p290 unless it's installed
$RVM_PATH/rvm info 1.9.2-p290 2&>1 >/dev/null || $RVM_SH install 1.9.2-p290
# run startup command inside rvm shell
$RVM_PATH/rvm-shell 1.9.2-p290 -c "cd /home/www-data/rails_app && bundle exec unicorn_rails -p 8000 -E production -c /home/www-data/rails_app/config/unicorn.rb -D"
This should give you the same result.

Resources