Mailx from within a C program? - c

I'm hoping to send a message via mailx to a list of recipients from within my C code.
I want to send an email containing the contents of the 'message' variable to everyone in the file /home/me/Email_List.txt.
if(send_email)
{
char* message = "Testing email";
//send contents of 'message' to everyone in /home/me/Email_List.txt
}
I need help with both the C program and the mailx command. Here's my mailx command that doesn't quite work:
//This works, but I don't want to send the contents of Email_List.txt
cat /home/me/Email_List.txt /home/me/Email_List.txt | mailx -t -s "Test"
//This doesn't work, error:
//cat: cannot open Test Text
cat /home/me/Email_List.txt "Test Text" | mailx -t -s "Test"
I could write my text to a file before sending it, but that seems inefficient.
Thoughts?

Working at the command line, I got this to work for me (with my normal corporate email address in place of me#example.com, of course):
mailx -s "Just a test" -t <<EOF
To: me#example.com
Subject: Just a test with a subject
Just testing mailx -t which seems to ignore -s options too
-=JL=-
EOF
The -s option subject line was ignored, as hinted in the body text. (This is a mailx version 12.5 6/20/10 on a machine running a derivative of Ubuntu 12.04 LTS.)
Note that the To: line is case-sensitive and space-sensitive (at least there must be a space after the colon). This is standard notation for the headers defined by RFC-822 (or whatever its current incarnation is). When I tried with the -s option but no Subject: line, I got a message without a subject in my inbox.
The following should work for you:
$ cat /home/me/Email_list.txt
To: My.email#company.com
Subject: Test email
$ { cat /home/me/Email_List.txt; echo "Test Text"; } | mailx -t
$
Note that blank line! Or you could use a plain echo; before the echo "Test text";. The semicolons are needed in the { ... } notation.

Related

My bash script that works in terminal does not work when run as a script

I have a simple bash script that goes to a webpage and scrapes the first installment of the Harry Potter novels and replaces each instance of "wand" with "butt." At the end, I wish to print the modified novel to the console but the script just halts and does not end. However, when I run each command separately in the terminal, the code works fine. I'm not sure what it is about running the actual .sh file that causes the final code to not run.
I know that the script runs up until the final echo command because it successfully creates the two output files.
Here is my script:
#!/bin/bash
# Harry Potter and the Sorcerer's Stone
touch output_file.txt
curl 'https://archive.org/stream/joannek.rowlingharrypotterbook1harrypotterandthephilosophersstoneenglishonlineclub.com/Joanne%20K.%20Rowling%20%28Harry%20Potter%2C%20Book%201%29%20-%20Harry%20Potter%20and%20the%20Philosophers%20Stone%20%5BEnglishOnlineClub.com%5D_djvu.txt' -o "output_file.txt"
tr "\n" "|" < output_file.txt | grep -o '<pre>.*</pre>' | sed 's/\(<pre>\|<\/pre>\)//g;s/|/\n/g' > parsed_output.txt
harry1=$( sed 's/<[^>]*>//g' parsed_output.txt )
harry1_butt="${harry1//wand/butt}"
harry1_butt="${harry1_butt//buttering/wandering}"
echo "$harry1_butt"
exit

assign two bash arrays with a single command

youtube-dl can take some time parsing remote sites when called multiple times.
EDIT0 : I want to fetch multiple properties (here fileNames and remoteFileSizes) output by youtube-dl without having to run it multiple times.
I use those 2 properties to compare the local file size and ${remoteFileSizes[$i]} to tell if the file is finished downloading.
$ youtube-dl --restrict-filenames -o "%(title)s__%(format_id)s__%(id)s.%(ext)s" -f m4a,18,webm,251 -s -j https://www.youtube.com/watch?v=UnZbjvyzteo 2>errors_youtube-dl.log | jq -r ._filename,.filesize | paste - - > input_data.txt
$ cat input_data.txt
Alan_Jackson_-_I_Want_To_Stroll_Over_Heaven_With_You_Live__18__UnZbjvyzteo__youtube_com.mp4 8419513
Alan_Jackson_-_I_Want_To_Stroll_Over_Heaven_With_You_Live__250__UnZbjvyzteo__youtube_com.webm 1528955
Alan_Jackson_-_I_Want_To_Stroll_Over_Heaven_With_You_Live__140__UnZbjvyzteo__youtube_com.m4a 2797366
Alan_Jackson_-_I_Want_To_Stroll_Over_Heaven_With_You_Live__244__UnZbjvyzteo__youtube_com.webm 8171725
I want the first column in the fileNames array and the second column in the remoteFileSizes.
For the time being, I use a while read loop, but when this loop is finished my two arrays are lost :
$ fileNames=()
$ remoteFileSizes=()
$ cat input_data.txt | while read fileName remoteFileSize; do \
fileNames+=($fileName); \
remoteFileSizes+=($remoteFileSize); \
done
$ for fileNames in "${fileNames[#]}"; do \
echo PROCESSING....; \
done
$ echo "=> fileNames[0] = ${fileNames[0]}"
=> fileNames[0] =
$ echo "=> remoteFileSizes[0] = ${remoteFileSizes[0]}"
=> remoteFileSizes[0] =
$
Is it possible to assign two bash arrays with a single command ?
You assign variables in a subshell, so they are not visible in the parent shell. Read https://mywiki.wooledge.org/BashFAQ/024 . Remove the cat and do a redirection to solve your problem.
while IFS=$'\t' read -r fileName remoteFileSize; do
fileNames+=("$fileName")
remoteFileSizes+=("$remoteFileSize")
done < input_data.txt
You might also interest yourself in https://mywiki.wooledge.org/BashFAQ/001.
For what it's worth, if you're looking for specific/bespoke functionality from youtube-dl, I recommend creating your own python scripts using the 'embedded' approach: https://github.com/ytdl-org/youtube-dl/blob/master/README.md#embedding-youtube-dl
You can set your own signal for when a download is finished (text/chime/mail/whatever) and track downloads without having to compare file sizes.

BCP command in Linux doesn't return the proper error code

In Linux/Unix based systems, whenever we execute a command in the shell and we echo the $?, the return value is 0 when its a success and the return value is 1 if the command fails.
So, if I am using the BULK COPY utility called BCP for SQL Server, and if the command fails when there is an error with the source file. For example, if I execute a bcp command like this.
/opt/bin/bcp <tablename> in <source_file> -S -U -P -D
and it says. "0 Rows Copied". It might be due to some errors in the source file. And, after that I do a echo $?. The value returned is still 0.
Is there a way we can capture the return value as 1, when encountered an error?
Thanks.
BCP doesn't document any return value. That's a shortcoming. What you can do is redirect output to a file, and look for error indications (probably, the text "Error").
To add a bit more detail to TT.'s answer, I write the bcp output to another file and then grep through it. My code looks like...
/opt/mssql-tools/bin/bcp "$TABLENAME" in $f \
-S $DEST_IP \
-U $USER -P $PASSWORD \
-d $DEST_DB \
-c \
-t "\t" \
-e $EXPORT_STAGE/$TABLENAME/$TABLENAME.$(basename $f).bcperror.log \
| tee $EXPORT_STAGE/$TABLENAME/$TABLENAME.$(basename $f).bcprun.log
# note here that I preserve the bcp output to can later in script
# look for error messages in the bcp process run itself (manually done since bcp does not throw error codes)
echo -e "\n Checking for error messages in bcp output\n"
if grep -q "Error" $EXPORT_STAGE/$TABLENAME/$TABLENAME.$(basename $f).bcprun.log
then
echo -e "\n\nError: error message detected in bcp process output, exiting..."
exit 255
fi
# can delete since already printing to stdout as well (and can just log the whole thing)
rm -f $EXPORT_STAGE/$TABLENAME/$TABLENAME.$(basename $f).bcprun.log

Handle ctrl +d programmatically?

I am trying to execute the following perl script.
##some code
$command = "nail -s this is a test $email";
system($command);
##some code
when I run this script, it hangs until I press CtrlD. after pressing CtrlD I get the desired result. My question is how can I hardcode CtrlD in my script?
I suppose you call mailx. nail ist most likely an alias. It expects input from STDIN, which is ended with CtrlD. You could workaround like this to send an empty mail:
$command = 'echo "" | nail -s SUBJECT ' . $email;
The mail program expects an . on a line alone to show it is the end of the message
Just make sure your $email contains a \n. and it should no longer hang.
The usual solution is to redirect it to read from /dev/null
Try to use this :
mail -s "Hello Test" -a Attachment email-address </dev/null
or, if you have any email body
mail -s "Hello Test" -a Attachment email-address <emailbodyfile.txt

BSD md5 vs GNU md5sum output format?

Any one knows why BSD md5 program produces hash output in this format ...
MD5 (checksum.md5) = 9eb7a54d24dbf6a2eb9f7ce7a1853cd0
... while GNU md5sum produces much more sensible format like this?
9eb7a54d24dbf6a2eb9f7ce7a1853cd0 checksum.md5
As far as I can tell, the md5sum format is much easier to parse and makes more sense. How do you do md5sum -check with md5? And what do the -p, -q, -r, -t, -x options mean? man md5 says nothing about those options! :|
On current OS X BSD systems you can specify the md5 -r command to get the expected output.
sgwilbur#gura:/vms/DevOps-v3.4$ md5 vmware*
MD5 (vmware-0.log) = 61ba1d68a144023111539abee08f4044
MD5 (vmware-1.log) = 97bc6f22b25833c3eca2b2cc40b83ecf
MD5 (vmware-2.log) = f92a281102710c4528d4ceb88aa0ac9b
MD5 (vmware.log) = 1f7858d361929d4bc5739931a075c0ad
Adding the md5 -r switch made the output look more like I was expecting, and easier to diff with the linux md5 sums that were produced from a Linux machine.
sgwilbur#gura:/vms/DevOps-v3.4$ md5 -r vmware*
61ba1d68a144023111539abee08f4044 vmware-0.log
97bc6f22b25833c3eca2b2cc40b83ecf vmware-1.log
f92a281102710c4528d4ceb88aa0ac9b vmware-2.log
1f7858d361929d4bc5739931a075c0ad vmware.log
This was the simplest approach for me to make is easy to diff from output generated by the md5sum command on a linux box.
Historical reasons, i guess. Meanwhile, -q suppress "MD5(...) = " output, so md5 -q checksum.md5 gives 9eb7a54d24dbf6a2eb9f7ce7a1853cd0
This is implied if md5 is not given any arguments and it reads from stdin.
Unfortunately md5sum in this case leaves "-" behind the checksum ("9eb7a54d24dbf6a2eb9f7ce7a1853cd0 -"),
so if you're looking for some generic function to return the checksum, here is what might help:
checksum() {
(md5sum <"$1"; test $? = 127 && md5 <"$1") | cut -d' ' -f1
}
checksum /etc/hosts
FreeBSD's man page says about the arguments -p Echo stdin to stdout and append the checksum to stdout.
-q Quiet mode ‐ only the checksum is printed out. Overrides the -r
option.
-r Reverses the format of the output. This helps with visual diffs.
Does nothing when combined with the -ptx options.
-t Run a built‐in time trial.
-x Run a built‐in test script.
I realize this is an old page, but I was making checksums on FreeBSD and checking them on Linux and I came across this page too. This page didn't help me solve the problem, so I came up with this small sed script to create the checksums on FreeBSD that match the Linux md5sum output:
md5 file [file ...] | sed -e 's#^MD5 [(]\(.*\)[)] = \(.*\)$#\2 \1#' > md5sums.txt
This will use the FreeBSD md5 command and rearrange the output to look like the GNU md5sum.
Then on Linux I can just use md5sum --check md5sums.txt
You can also use the above sed script with an existing file produced by FreeBSD's md5 command.
I also put this alias in my FreeBSD .cshrc file:
alias md5sum "md5 \!* | sed -e '"'s#MD5 [(]\(.*\)[)] = \(.*\)$#\2 \1#'"'"
now on FreeBSD I can just say md5sum file1 file2 file3 ... and it just works.
One can use the GNU md5sum -c checksum.md5 that will look for checksum file and check against the checksum.md5 file content.
md5sum -c checksum.md5 | grep "checksum: OK" -
Example inside a Ruby system call to check against a BSD formatted .md5 file:
system("md5sum -c checksum.md5 | grep \"checksum: OK\" -")
This will return true or false.

Resources