Get output from executing an applescript within a bash script - linux

I tried this technique for storing the output of a command in a BASH variable. It works with "ls -l", but it doesn't work when I run an apple script. For example, below is my BASH script calling an apple script.
I tried this:
OUTPUT="$(osascript myAppleScript.scpt)"
echo "Error is ${OUTPUT}"
I can see my apple script running on the command line, and I can see the error outputting on the command line, but when it prints "Error is " it's printing a blank as if the apple script output isn't getting stored.
Note: My apple script is erroring out on purpose to test this. I'm trying to handle errors correctly by collecting the apple scripts output

Try this to redirect stderr to stdout:
OUTPUT="$(osascript myAppleScript.scpt 2>&1)"
echo "$OUTPUT"

On success, the script's output is written to STDOUT. On failure, the error message is written to STDERR, and a non-zero return code set. You want to check the return code first, e.g. if [ $? -ne 0 ]; then..., and if you need the details then you'll need to capture osascript's STDERR.
Or, depending what you're doing, it may just be simplest to put set -e at the top of your shell script so that it terminates as soon as any error occurs anywhere in it.
Frankly, bash and its ilk really are a POS. The only half-decent *nix shell I've ever seen is fish, but it isn't standard on anything (natch). For complex scripting, you'd probably be better using Perl/Python/Ruby instead.

You can also use the clipboard as a data bridge. For example, if you wanted to get the stdout into the clipboard you could use:
osascript myAppleScript.scpt | pbcopy
In fact, you can copy to clipboard directly from your applescript eg. with:
set the clipboard to "precious data"
-- or to set the clipboard from a variable
set the clipboard to myPreciousVar
To get the data inside a bash script you can read the clipboard to a variable with:
data="$(pbpaste)"
See also man pbpase.

Related

Get bash autocompletion printed by stdin write

I want to write a program that will print out the autocompletions of bash.
Basically I'm writting something into bash stdin with
childProc.stdin.write("./myfi")
And would like to receive autocompletion for it like "./myfile.txt"
But childProc.stdout is empty after childProc.stdin.write("\t") so there has to be some other way to trigger autocompletion.
Any ideas?
Command-completion in only enabled in interactive shells. Bash is interactive if:
Neither a script filename nor the -c option were specified when invoking bash, and
both stdin and stderr are attached to terminals (as determined by isatty()), or
bash was started with the -i flag.
In your case, stdin is clearly a pipe, which is not a terminal. So probably command completion has been disabled. But if it were enabled, you'd see the result on stderr not stdout.
So you could try supplying the -i command line option when starting your bash shell, or you could attach its stdin, stdout and stderr file descriptors to a pseudo-tty. In either case, what you will see coming back from bash will be intermingled with terminal control codes, so you'll probably want to set TERM to something basic (like dumb).
If you want to see the completions which bash might generate, you can use the compgen built-in. compgen does not know about the customized completion settings installed by the complete command, and it is not easy to get the environment set up correctly for the -F and -C function, but other than that you can probably get it to generate whatever completion lists you would like. See the Bash manual for detailed option documentation.
I've found an answer.
The thing that made it work was Pseudoterminal.
This module actually.
https://www.npmjs.com/package/pty.js-dl

shell prompt seemingly does not reappear after running a script that uses exec with tee to send stdout output to both the terminal and a file

I have a shell script which writes all output to logfile
and terminal, this part works fine, but if I execute the script
a new shell prompt only appear if I press enter. Why is that and how do I fix it?
#!/bin/bash
exec > >(tee logfile)
echo "output"
First, when I'm testing this, there always is a new shell prompt, it's just that sometimes the string output comes after it, so the prompt isn't last. Did you happen to overlook it? If so, there seems to be a race where the shell prints the prompt before the tee in the background completes.
Unfortunately, that cannot fixed by waiting in the shell for tee, see this question on unix.stackexchange. Fragile workarounds aside, the easiest way to solve this that I see is to put your whole script inside a list:
{
your-code-here
} | tee logfile
If I run the following script (suppressing the newline from the echo), I see the prompt, but not "output". The string is still written to the file.
#!/bin/bash
exec > >(tee logfile)
echo -n "output"
What I suspect is this: you have three different file descriptors trying to write to the same file (that is, the terminal): standard output of the shell, standard error of the shell, and the standard output of tee. The shell writes synchronously: first the echo to standard output, then the prompt to standard error, so the terminal is able to sequence them correctly. However, the third file descriptor is written to asynchronously by tee, so there is a race condition. I don't quite understand how my modification affects the race, but it appears to upset some balance, allowing the prompt to be written at a different time and appear on the screen. (I expect output buffering to play a part in this).
You might also try running your script after running the script command, which will log everything written to the terminal; if you wade through all the control characters in the file, you may notice the prompt in the file just prior to the output written by tee. In support of my race condition theory, I'll note that after running the script a few times, it was no longer displaying "abnormal" behavior; my shell prompt was displayed as expected after the string "output", so there is definitely some non-deterministic element to this situation.
#chepner's answer provides great background information.
Here's a workaround - works on Ubuntu 12.04 (Linux 3.2.0) and on OS X 10.9.1:
#!/bin/bash
exec > >(tee logfile)
echo "output"
# WORKAROUND - place LAST in your script.
# Execute an executable (as opposed to a builtin) that outputs *something*
# to make the prompt reappear normally.
# In this case we use the printf *executable* to output an *empty string*.
# Use of `$ec` is to ensure that the script's actual exit code is passed through.
ec=$?; $(which printf) ''; exit $ec
Alternatives:
#user2719058's answer shows a simple alternative: wrapping the entire script body in a group command ({ ... }) and piping it to tee logfile.
An external solution, as #chepner has already hinted at, is to use the script utility to create a "transcript" of your script's output in addition to displaying it:
script -qc yourScript /dev/null > logfile # Linux syntax
This, however, will also capture stderr output; if you wanted to avoid that, use:
script -qc 'yourScript 2>/dev/null' /dev/null > logfile
Note, however, that this will suppress stderr output altogether.
As others have noted, it's not that there's no prompt printed -- it's that the last of the output written by tee can come after the prompt, making the prompt no longer visible.
If you have bash 4.4 or newer, you can wait for your tee process to exit, like so:
#!/usr/bin/env bash
case $BASH_VERSION in ''|[0-3].*|4.[0-3]) echo "ERROR: Bash 4.4+ needed" >&2; exit 1;; esac
exec {orig_stdout}>&1 {orig_stderr}>&2 # make a backup of original stdout
exec > >(tee -a "_install_log"); tee_pid=$! # track PID of tee after starting it
cleanup() { # define a function we'll call during shutdown
retval=$?
exec >&$orig_stdout # Copy your original stdout back to FD 1, overwriting the pipe to tee
exec 2>&$orig_stderr # If something overwrites stderr to also go through tee, fix that too
wait "$tee_pid" # Now, wait until tee exits
exit "$retval" # and complete exit with our original exit status
}
trap cleanup EXIT # configure the function above to be called during cleanup
echo "Writing something to stdout here"

what the meaning of this link in linux script

What is the meaning of the following which is on the top of linux script
#!/bin/bash
return &> /dev/null
The line is to protect users from sourcing the script.
When the script is run (not sourced but run), the script will proceed to the next lines until the end of file.
When the script is sourced, the script will just return and do nothing.
return is supposed to return value from bash function.
When used exactly like in your example but without &> /dev/null, it is invalid use because return does not belong to body of bash function, and would print:
line 2: return: can only `return' from a function or sourced script
However, somebody decided to hide that error message by piping output to /dev/null.
In other words, this all does not make much sense.
This discards the unwanted output of your program. Please check out this link, differences between >, 2> and &> are very well explained over there.
Quoting:
command &>/dev/null
This syntax redirects both standard output and error output messages to /dev/null where it is ignored by the shell.

Run a shell command through Perl in a specific terminal

First off, I am pretty new to Perl so I may be missing something obvious. This is not the typical "I want to run a shell command through Perl" question.
I don't want to capture all of the shell output. I have a program/script that intelligently writes to the terminal. I didn't write it and don't know how it all works, but it seems to move the view to the appropriate place after printing some initialization, then erase previous terminal output and write over it (updates) until it finally completes. I would like to call this from my perl script rather than printing everything to a file to grab it after, since printing to a file does not keep the intelligence of the printout.
All I need to do is:
open an xterm in my perl script
make a system call in that terminal
have that terminal stay up until I manually exit it
Can I do this in perl?
Thanks.
system 'xterm', '-hold', '-e', $program;
where $program is the terminal-aware program you want to run.
-hold causes xterm to stay open after the program exits, waiting for you to close it manually.
-e specifies the program or command line to run. It and its argument must appear last on the xterm command line.
Try doing this by example :
#!/usr/bin/env perl
use strict; use warnings;
use autodie;
open my $term, '| xterm -hold -e $(</dev/stdin)';
foreach my $dir (qw|/etc /usr /home|) {
print $term "ls $dir\n"; # do anything else you'd like than "ls $dir" here
}
close $term;

Shell script : how to output to command line?

I'm making a shell script and I want to know if it's possible to write directly to the command line when the script is executed ?
Example :
user#localhost:/home/user$./script.sh
... output
... another output
... another output
... last output
user#localhost:/home/user$I want to write here on the command line
I don't want to "echo" some text, I want to write directly at the prompt.
Thanks!
No, you can't do that. If you want user to invoke your provided command after your script is finished - why not just prompt user for confirmation?
If you just want the text to show up there, but not be able to do anything with it, you can do this.
File test.sh:
echo "Output"
./test2.sh &
File test2.sh:
echo "Output2"
Notice how the first script calls the second script with the & at the end.
In this case, "Output2" will be written to the prompt, but it can't be deleted and will have no effect on the next command at all. But if this is something you're doing to grab the user's attention, it would work.
In ksh:
print -s $(script)
will print to the command history. Wrap this in a function and you'll have something close to what you are asking for.
If you are using X environment install xclip and xdotool, then:
#!/bin/bash
your scripts....
echo -n your command to write 2>&1|xclip
xdotool click 2

Resources