What is the difference between execute, test and capture commands in Capistrano? - ruby

On SSHkit-Github it's says:
All backends support the execute(*args), test(*args) & capture(*args)
From SSHkit-Rubydoc, I understand that execute is actually an alias to test?
What is the difference between test, execute, capture in Capistrano/SSHKit and when should I use either?

execute
just executes command.
raises error with non-0 exit.
test
method behaves exactly the same as execute however it returns boolean (true if command exits with a 0 exit, and false otherwise). it'll usually be used for control flow in your tasks.
capture
method will execute the command on the first matching server, and will return the stdout output of the command as a string. stderr output will be ignored (use ls 2>&1 to redirect stderr to stdout).
raises error with non-0 exit.

Related

Exiting a shell script with an error

basically I have written a shell script for a homework assignment that works fine however I am having issues with exiting. Essentially the script reads numbers from the user until it reads a negative number and then does some output. I have the script set to exit and output an error code when it receives anything but a number and that's where the issue is.
The code is as follows:
if test $number -eq $number >dev/null 2>&1
then
"do stuff"
else
echo "There was an error"
exit
The problem is that we have to turn in our programs as text files using script and whenever I try to script my program and test the error cases it exits out of script as well. Is there a better way to do this?
The script is being run with the following command in the terminal
script "insert name of program here"
Thanks
If the program you're testing is invoked as a subprocess, then any exit command will only exit the command itself. The fact that you're seeing contrary behavior means you must be invoking it differently.
When invoking your script from the parent testing program, use:
# this runs "yourscript" as its own, external process.
./yourscript
...to invoke it as a subprocess, not
# this is POSIX-compliant syntax to run the commands in "yourscript" in the current shell.
. yourscript
...or...
# this is bash-extended syntax to run the commands in "yourscript" in the current shell.
source yourscript
...as either of the latter will run all the commands -- including exit -- inside your current shell, modifying its state or, in the case of exit, exec or similar, telling it to cease execution.

Understanding exec command

Looking for some basic help in shell programming.
Suppose we have a command known as foobar, then what is the effect of shell invocation
exec foobar
exec 2> /var/log/foobar.log
The first exec command should only be used in a script — not at a command line terminal. It replaces the shell with the program foobar, instead of running it as a separate child process. Any commands in the script after the exec foobar will not be executed (even if the shell fails to find foobar to execute); if it is an interactive terminal session, it will report the error and continue.
exec [-cl] [-a name] [command [arguments]]
If command is supplied, it replaces the shell without creating a new process. If the -l option is supplied, the shell places a dash at the beginning of the zeroth argument passed to command. This is what the login program does. The -c option causes command to be executed with an empty environment. If -a is supplied, the shell passes name as the zeroth argument to command. If command cannot be executed for some reason, a non-interactive shell exits, unless the execfail shell option is enabled. In that case, it returns failure. An interactive shell returns failure if the file cannot be executed.
The second exec (with I/O redirection but no command) changes things so that the standard error stream goes to the file /var/log/foobar.log. Any further error messages from the shell, or from commands executed by the shell, go to the log file (unless there's another lot of I/O redirection).
If no command is specified, redirections may be used to affect the current shell environment. If there are no redirection errors, the return status is zero; otherwise the return status is non-zero.
exec foobar
will replace your shell process with foobar. I do not think you mean exec 2>/var/log/foobar.log but rather exec foobar 2>/var/log/foobar.log. This will do the same with sending 2 i.e. standard error messages to specified log file. You can read man page here.
exec(1) command is similar to exec(3) call. It replaces the code segment of calling process from that of called program. 1 and 3 signify man page sections.

Net::SSH::Shell::Process $DONTEVERUSETHIS

When using Net::SSH to run commands on a remote connection, it adds the following script to the end of each and every command:
DONTEVERUSETHIS=$?; echo #{manager.separator} $DONTEVERUSETHIS; echo \"exit $DONTEVERUSETHIS\"|sh
the output produced looks like:
DONTEVERUSETHIS=$?; echo 10e75e2821012645fa3a3cc08ec5de527a392af68db4c3cac63dac22d4de2a8708fcc176190817fe $DONTEVERUSETHIS; echo "exit $DONTEVERUSETHIS"|sh
Here's a link to the source code Net::SSH::Shell::Process and look at the 'run' method
Can anyone explain why this is always added?
It doesn't appear in the console output but plays hell with parsing ~/.bash_history
A quick look into the source repository reveals this commit:
keep the exitcode 1 available for the next command
In effect, this allows you to inspect the value of $? (i.e. the exitcode of the previous command) in the next command.
TL;DR: It's the machine readable equivalent of a colored shell prompt. It's there to tell the library when the issued command has finished, and whether it was successful.
When running a command with Net::SSH (not ::Shell), here's what happens:
Connection is established
Command is sent
Output is received
The command exits, sshd returns the exit code and ends the connection.
This means that it's easy to:
Get the output: just read until sshd closes the connection.
Get the exit code. sshd returns it.
However, it means that each command is run in a separate session, so cd /tmp followed by pwd will return /home/youruser because these are two different sessions, so the former doesn't affect the latter.
The purpose of Net::SSH::Shell is instead to run multiple, individual commands in the same shell session:
Connection is established.
Commands are sent as a single, infinite, concatenated stream
Output is received as a single, infinite, concatenated stream
This leaves two open questions:
How do you know whether the command has finished or whether it's still processing?
How do you get the exit code now that sshd doesn't return it?
The way Net::SSH::Shell solves this is by modifying the command in the way you saw, to make it print a unique ID and exit code when done:
To get the command's output, read until a line with the unique ID is printed.
To get the exit code, read it from the same line.

Shell logout after exec redirection for stdin

As described in advanced bash script-guide, exec can be used to redirect I/O.
So I just write some cases in my shell. Redirecting stdout or stderr works well, but redirecting stdin makes the shell logout. Any explanation?
Commands:
exec < file
The shell exits when it reaches EOF on its standard input (that's why you type Control-D to logout). When it has finished reading from file, it will exit as there is no more input to come.
from bash's BASH_BUILTINS man page (man exec)
exec [-cl] [-a name] [command [arguments]]
If command is specified, it replaces the shell. No new process
is created. The arguments become the arguments to command. If
the -l option is supplied, the shell places a dash at the begin-
ning of the zeroth argument passed to command. This is what
login(1) does. The -c option causes command to be executed with
an empty environment. If -a is supplied, the shell passes name
as the zeroth argument to the executed command. If command can-
not be executed for some reason, a non-interactive shell exits,
unless the shell option execfail is enabled, in which case it
returns failure. An interactive shell returns failure if the
file cannot be executed. If command is not specified, any redi-
rections take effect in the current shell, and the return status
is 0. If there is a redirection error, the return status is 1.
So, as you can see, if a command finishes -> exit, and if a command fails -> exit...
Redirecting a file into exec will fail...
Unless it contains a line that is a valid code that also doesn't exit till you quit it.
(otherwise it will run, and exit...)

Why do we pass 0 as a parameter to "exit"?

In the book learn ruby the hard way, I found a syntax to exit from the program:
Process.exit(0)
Why is the parameter 0 being passed in the exit method here even though it works if I pass another integer or do not pass any parameter? What is the significance of 0?
This is an 'exit code'.
This exit code has special meaning in some cases (see for example http://tldp.org/LDP/abs/html/exitcodes.html)
You can pass whatever you want, if the code isn't caught after, this will have no effects.
Here '0' is for 'Everything works fine !'
It is because when a child process is started (child process being your Ruby script in that case) the parent process (shell, system, etc.) can wait for it to finish.
Once it's finished, it can tell the parent process what is the status of it's execution. Zero usually means that the execution has been successfull and completed without any errors.
If you, on example, run your script from bash shell, and it will call Process.exit(0), you could check if it succeeded using $? variable:
$ ./my_ruby.script # calls Process.exit(0)
$ echo $?
0 # ok, script finished with no errors.

Resources