In my app, a user can run a script, and if it is run in the terminal, it shows a nice progress bar, how would I replicate this in rails? I mean I could do like something between the two to communicate, but I would prefer if it would just show a "live" shell output.
Thanks :)
If your script is invoked with 2>&1 at the end, backticks invocation will return STDOUT & STDERR.
result = ‘ls 2>&1‘
Related
I'm trying to execute .sh file in rails index action.
I try exec"sh app/controllers/file.sh"
it's execute it in terminal then stop the server! I don't know why.
And I try output = system"sh app/controllers/file.sh" it's return true in the browser not what is in the .sh file
Thanks in advance :)
You'll want to look at the Open3 class, specifically capture2 or capture3:
require 'open3'
stdout, stderr, status = Open3.capture3("sh app/controllers/myscript.sh")
As you can see above capture3 will get you the stdout, stderr, and status of your script run. While capture2 will just return stdout and status. There are other useful functions in Open3 which are worth looking at.
To understand why exec and system are behaving the way they are, you can read this SO answer: Ruby, Difference between exec, system and %x() or Backticks
I have a two scripts in the Rails environment which have to run 24/7. I'm working on a remote server, so I need to start the scripts using ssh, which means I need to keep the ssh windows open all the time.
I'm searching for a simple way to run these scripts in the background so they aren't canceled as soon as I close the ssh connection.
I don't want to use screen. I think there must be simpler way to handle this. Isn't there?
I think the most basic solution would be nohup:
nohup myscript &> /dev/null &
You can disown a script:
ruby script.rb &!
STDOUT/STDERR are still attached to the current shell, but the ruby process isn't a child of the shell anymore, so it won't get killed if you close the terminal.
Check Daemons. It's a toolkit for converting a script to a controllable daemon.
You can use
runit
supervisord
For daemonizing
Or some ruby stuff: https://www.ruby-toolbox.com/#Background_Processing for background processing
I'm having a weird issue with a start-up script which runs a Sinatra script using the shell's "daemon" function. The problem is that when I run the command at the command line, I get output to STDOUT. If I run the command at the command line exactly as it is in the script -- less the daemon part -- the output is correctly redirected to the output file. However, when the startup script runs it (see below), I get stuff to the STDERR log but not to the STDOUT log.
The relevant lines of the script:
#!/bin/sh
# (which is and has been a symlink to /bin/bash
# Source function library.
. /etc/init.d/functions
# Set Some Variables
RUNAS="joeuser"
PID=/var/run/myapp.pid
LOG="/var/log/myapp/app-out.log"
ERR_LOG="/var/log/myapp/app-err.log"
APPLICATION_COMMAND="RAILS_ENV=production ruby /opt/myapp/lib/daemons/my-sinatra-app.rb -p 8002 2>>${ERR_LOG} >>${LOG} &"
# Snip a bunch. This is the applicable line from the "start" case:
daemon --user $RUNAS --pidfile $PID $APPLICATION_COMMAND &> /dev/null
Now, the funky parts:
The error log is written to correctly via the redirect of STDERR.
If I reverse the order of the >> and the 2>> (I'm grasping at straws, here!), the behavior does not change: I still get STDERR logged correctly and STDOUT is empty.
If the output log doesn't exist, the STDOUT redirect creates the file. But, the file remains 0-length.
This used to work. The log directory is maintained by log-rotate. All of the more-recent 'out' logs are 0-length. The older ones are not. It seems like it stopped working some time in April. The ruby code didn't change at any time near then; neither did the startup script.
We're running three different services in this way. Two of them are ruby daemons (one uses sinatra, one does not) and the other is a background java process. This is occurring for BOTH of the ruby processes but is not happening on the java process. Maybe something changed in Ruby?
FTR, we've got ruby 1.8.5 and RHEL 5.4.
I've done some more probing. The daemon function does a bunch of stuff, but the meat of the matter is that it runs the program using runuser. The command essentially looks like this:
runuser -s /bin/bash - joeuser -c "ulimit -S -c 0 >/dev/null 2>&1 ; RAILS_ENV=production ruby /opt/myapp/lib/daemons/my-sinatra-app.rb -p 8002 '</dev/null' '>>/var/log/myapp/app-out.log' '2>>/var/log/myapp/app-err.log' '&'"
When I run exactly that at the command line (both with and without the single-ticks that got added somewhere along the line), I get the exact same screwy behavior w.r.t. the output log. So, it seems to me that this is an issue of how ruby (?) interacts with runuser?
Too long to put in a comment :-)
change the shebang to add #!/bin/sh -x and verify that everything is expanded according to your expectations. Also, when executing from terminal, your .bashrc file is sourced, when executing from script, it is not; might be something in you're environment that differ. One way to find out is to do env from terminal and from script and diff the output
env > env_terminal
env > env_script
diff env_terminal env_script
Happy hunting...
I wrote a script that does maintenance tasks for a rails application. The script uses a class that uses models defined in the application. Just an example, let's say application defines model User, and my class (used within the script), sends messages to it, like User.find id.
I am looking for ways to optimize this script, because right now it has to load the application environment: require '../config/environment'. This takes ~15 seconds.
Had the script not use application codebase to do its job, I could have replaced model abstractions with raw SQL. But unfortunatly I can't do that because I would have to repeat the code in the script that is already present in the codebase. Not only would this violate DRY principle and require alot of work, the script would not be very maintainable, in case the model methods that I am using change.
I would like to hear ideas how to approach this problem. The script is not run from the application itself, but from the shell (with Capistrano for instance).
I hope I've described the problem clear enough. Thank you.
Could you write a little daemon that is in a read on a pipe (or named fifo, or unix domain socket, or, with more complexity, a tcp port) that accepts 'commands' that would be run on your database?
#!/usr/bin/ruby
require '../config/environment'
while (true) do
File.open("/tmp/fifo", "r") do |f|
f.each_line do |line|
case line
when "cleanup" then puts "clean!"
when "publish" then puts "published!"
else puts "invalid command, ignoring"
end
end
end
end
You could start this thing up with vixie cron's #reboot specifier, or you could run it via capistrano commands, or run it out of init or init scripts. Then you write your capistrano rules (that you have now) to simply echo commands into the fifo:
First,
mkfifo /tmp/fifo
In one terminal:
$ ./env.rb
In another terminal:
$ echo -n "cleanup" > /tmp/fifo
$ echo -n "publish" > /tmp/fifo
$ echo -n "go away" > /tmp/fifo
The output in the first terminal looks like this:
clean!
published!
invalid command, ignoring
You could make the matching as friendly (perhaps allow plain echo, rather than require echo -n as my example does) or unfriendly as you want. And the commands that get run can of course call into your model files to do their work.
Please make sure you choose a good location for your fifo -- /tmp/ is probably a bad place, as many distributions clear it on reboot. Also make sure you set the fifo owner and permission (chown and chmod) appropriately for your application -- you might not want to allow your Firefox's flash plugin to write to this file and command your database.
This would be part of a reverse-engineering project.
To determine and document what a shell script (ksh, bash, sh) does, it is comfortable, if you have information about what other programs/scripts it calls.
How could one automate this task? Do you know any program or framework that can parse a shell script? This way for instance, I could recognize external command calls -- a step to the right direction.
For bash/sh/ksh, I think you can easily modify their source to log what has been executed. That would be a solution.
How about:
Get a list of distinct words in that script
Search $PATH to find a hit for each
?
bash -v script.sh ?
Bash's xtrace is your friend.
You can invoke it with:
set -x at the top of your script,
by calling your script with bash -x (or even bash --debugger -x),
or recursively by doing (set -x; export SHELLOPTS; your-script; )
If you can't actually run the script, try loading it into a text editor that supports syntax highlighting for Bash. It will color-code all of the text and should help indicate what is a reserved word, variable, external command, etc.