today I was trying to replace a bash script with a groovy script. Everything runs smooth and I managed to use the execute() command to invoke other command.
Then I was trying to send an email with a subject:
mail -s "this is a test" my.mail#example.com < mail.tmp
turned into
'mail -s "this is a test" my.mail#example.com < mail.tmp'.execute()
does not work since groovy will split up the one argument "this is a test" into four arguments "this is a test".
So far so good. Google helped me to turn this into
['mail', '-s', "this is a test", 'my.mail#example.com', '<', 'mail.tmp'].execute()
Now the subject is recognized as one parameter, but the < is also recognized as parameter and not as the file redirection.
Any idea how I could solve this?
PS: no, I would not like to use java code for sending mail since I guess the code will be more complex. But if you have a java one-liner, you are welcome...
You'll have to handle writing the output from the process to a file ...
new File('mail.tmp').withWriter { it << """mail -s "this is a test" my.mail#example.com""".execute().getText() }
I only tested above with "ls -al" as the command and it worked as expected, I'm not sure if a longer running process would require you to tweak the way you go about it-- if so you might need to use waitForProcessOutput:
new File('mail.tmp').withWriter { """mail -s "this is a test" my.mail#example.com""".execute().waitForProcessOutput(it, it) }
Found another solution which looks easier to me, but I guess isn't as clean as the one provided by #chrixian:
['sh','-c','mail -s "this is a test" my.mail#example.com < mail.tmp'].execute()
this command creates another shell in order to execute the mail command. This way, the 'mail -s "this is a test" my.mail#example.com < mail.tmp' is interpreted by a shell and it knows how to correctly handle the parameters and < symbol.
Drawback: it works on *nix systems. For windows systems, the shell is executed in a different way.
Related
I wrote a shell script that I use under ash, and I redirect stderr and stdout to a log file. I would like that log file to be emailed to me only if stderr is not empty.
I tried:
exec >mylog.log 2>&1
# Perform various find commands
if [TEST_IF_STDERR_NOT_EMPTY]; then
/usr/bin/mail -s "mylog" email#mydomain.com < mylog.log
fi
My question is twofold:
1- I get a -sh: /usr/bin/mail: not found error. It seems that the mail command doesn't exist under ash (or at least under my linux box, which is a Synology NAS), what would be the alternative? Worst case, perl is available, but I would prefer to use standard sh commands.
2- How to I test that stderr is not empty?
Thanks
How to check if file is empty in bash
As for the first question, in your code you are calling mail but lower in the post you are calling email. Check your code and make sure it is mail.
Use which mail to get the full path. Maybe it is not installed in /usr/bin/.
Use find to locate mail.
If you can go to another shell, run it and then execute which mail to get the full path of mail in case the path is set up in the alternative shells.
I have been messing around with voice commands, but ran into a snag. I am trying to get a terminal command to run but it is not working. The command makes asterisks "snow" fall.
This is what I have so far.
tell application "Terminal"
activate
run script "ruby -e 'C=`stty size`.scan(/\d+/)[1].to_i;S=["2743".to_i(16)].pack("U*");a={};puts "\033[2J";loop{a[rand(C)]=0;a.each{|x,o|;a[x]+=1;print "\033[#{o};#{x}H \033[#{a[x]};#{x}H#{S} \033[0;0H"};$stdout.flush;sleep 0.1}'"
end tell
All I get are errors
Command line scripts executed with the do shell script command. The string escaping can get a bit gnarly, so be careful with that too. Here's a simple example:
do shell script "say \"Today is `php -r \"echo date('l');\"`\""
EDIT:
OK, I just realised your script actually depends on having a Terminal window to run in, so the usual approach of do shell script won't work here.
There are still a lot of unescaped quotation marks in your Applescript, but rather than fixing those, I think it would be easier to put the whole ruby script into a stand-alone file and pass that to Terminal instead.
stars.rb
#!/usr/bin/ruby
C=`stty size`.scan(/\d+/)[1].to_i;
S=["2743".to_i(16)].pack("U*");
a={};
puts "\033[2J";
loop {
a[rand(C)]=0;
a.each {
|x,o|;
a[x]+=1;
print "\033[#{o};#{x}H \033[#{a[x]};#{x}H#{S} \033[0;0H"
};
$stdout.flush;
sleep 0.1
}
AppleScript
tell application "Terminal"
activate
do script "~/stars.rb"
end tell
An easy way to escape a shell command for AppleScript is to save the command in a text file. Run the script below and copy the Result.
set myText to read (choose file) as «class utf8»
I am running script with arguments inside the perl script. script and arguments are enclosed with backticks. When I use '&' symbol at last after arguments, the command is not running on background, it is running on foreground. can someone find the mistake in my program. I need to save the output and redirect the same to one variable and then to log.
Below is the code of mine:
open (MYSM, "> /logs/${SM}.smlog");
open (MYSP, "> /logs/${SM}.splog");
$SM_LOG_VAR = ` ./sm.sh $SE_VER $SMS_VERSION & ` ;
$SP_LOG_VAR = ` ./sp.sh $SE_VER $SMS_VERSION ` ;
print MYSM $SM_LOG_VAR ;
print MYSP $SP_LOG_VAR ;
close(MYSM);
close(MYSP);
The line :
$SM_LOG_VAR = ` ./sm.sh $SE_VER $SMS_VERSION & ` ;
is not running in background which is completely enclosed with backticks.
The backticks themselves will complete only when the command completes. You want something like fork + exec or perhaps dup2. Anyway, how would the program proceed with a value for $SM_LOG_VAR if the command to obtain that information has not yet finished?
I think your asking the wrong question, from reading your code let me guess at your real problem. You have a Perl script that does some work not shown to set some variables that are then used to run 2 external programs. You want to run both programs simultaneously and store the output from each to it's own log file.
The simplest way to accomplish this is to run both programs in the background and have the shell do the redirection.
system("./sm.sh $SE_VER $SMS_VERSION > /logs/${SM}.smlog &");
system("./sp.sh $SE_VER $SMS_VERSION > /logs/${SM}.splog &");
This will return to your script without waiting for either program to finish, if you have code later in the program that requires that the commands be completed then you will may need a more complex solution.
I would look at:
Perl Backticks
If you want to run it in the background I would try something like open3:
IPC::Open3
I am using CakePHP 1.3 and I was able to successfully able setup the cron job to run shells using the example that was given in the CakePHP Book.
*/5 * * * * /full/path/to/cakeshell myshell myparam -cli /usr/bin -console /cakes/1.2.x.x/cake/console -app /full/path/to/app >> /path/to/log/file.log
This outputs the results into a log file but I want to receive email when there is an error so I can try to resolve the problem.
I tried the following with no luck.
If I remove the >> /path/to/log/file.log then even the successful run is emailed.
> /dev/null, my assumption was it would send a successful to /dev/null and error to email.
1> /dev/null, tried another variation of 2
Any help is appreciated.
Thanks
Huseyin,
This is not a CakePHP error then, and is maybe a question better suited for serverfault, as you would script your solution.
Bash's built-in facilities are up to the task, try The linux documentation project's neat introductory tutorials on shell scripting and #man bash.
Your solution basically has to use a temporary file or variable in which you store the output of the last cron job run. If there is an error:
cat THE_TMP_FILE | mail -s "Error from Server Huseyin's server" huseyin#fancy_domain.com
else:
cat THE_TMP_FILE >> blah.blah.log
Unfortunatly, you need a MTA available, in order to make the mail command. If you do not have access to the mail command, then you set another cron job following the first in time which then simply runs a if [ -e THE_FILE_CONTAINING_THE_LAST_ERROR]; then { echo $(cat THE_FILE_CONTAINING_THE_LAST_ERROR); rm -v THE_FILE... ;} ; fi
Of course this is not working code, but pretty close, so you'll get the idea.
I am using sendmail in perl and noticed (after much banging of head against wall) that when the script is run at the command line it needs you to leave out the \n(s) after your e-mail and the recipient's email address in order to format the mail correctly, but when running via CGI if those \n(s) aren't there it returns an error stating that the recipient's e-mail is malformed.
Has anyone else encountered this? What are the two doing differently?
I am betting that you are getting data from prompts in on the commandline and not chomping them like this:
my $send_to = <>;
This means $send_to will already have a "\n". To make them both work the same way chomp the variables:
my $send_to = <>;
chomp($send_to);
or just
chomp(my $send_to = <>);
In a couple of your comments you mention that you're running the script from the command line with the -l option (perl -l foo.cgi).
The -l option enables automatic line-ending processing, and as your problem is with line endings, I suggest you try it without the -l.
Where is the data coming from? Hard coded in the script, or from a web form?
Just as an aside, if you get the recipient's email address from a web form, your form will be used by spammers. It's a 100% guarantee.
The term "CGI" is broad, if you mean your perl script run as a CGI versus yur perlscript run at the command line, I would look toward the pathing that the script has and its general inherited environment. Especially if your running it as different userids. If the webserver is in a chroot, etc.
use Data::Dumper;
warn(Dumper(\%ENV));
So I'm guessing that you have something like this for running it via the command line:
my $your_email = "you#foo.bar";
my $recipient_email = "them#foo.bar";
and this when "running via CGI":
my $your_email = "you#foo.bar\n";
my $recipient_email = "them#foo.bar\n";
So the question I would ask you then is how you're calling sendmail with the above variables, and also what you mean when you say "running via CGI" versus running via the command line? Are you just adding CGI code and still running via the command line or by visiting its URL in a web browser?