Suppose I have a file BOD which contains lines of text and a file ADDR which contains e-mail addresses. How can I send the first line of BOD to the first address in ADDR, the second line of BODIES to the second line in ADDR, ... until the last line?

I know that you can send a mail in the shell using


but how can you repeat this task for each line?

  • Please edit your question and show us an example of your BOD and ADDR files. – terdon Feb 24 '16 at 11:58

Using the following variables,


lines_in_text=$( cat "$text_file" | wc -l )
lines_in_addr=$( cat "$mail_file" | wc -l )


You can write the following routine:

send_mail() {
    while [[ "$line_num" -le "$lines_in_text" ]]; do
        text_line=$( sed -n "${line_num}p" "$text_file" )
        mail_line=$( sed -n "${line_num}p" "$mail_file" )
        echo "$text_line" | mail "$mail_line"
        line_num=$(( line_num + 1 ))


Then you can use your script as follows:

./script BOD ADDR

Edit: An alternative way of doing this would be reading each of the text and address files into separate arrays, whereby every index contains a line of the respective file, as such:


IFS=$'\n' read -d '' -r -a texts < "$1"
IFS=$'\n' read -d '' -r -a mails < "$2"

send_mail_alternate() {
    for (( i = 0; i < "${#texts[@]}"; i++ )); do
        echo "${texts[i]}" | mail "${mails[i]}"


Here, the two arrays created are texts and mails. "${#texts[@]}" represents the total number of lines in array texts, and each line can be accessed by "${texts[i]}" or "${mails[i]}", where i starts from 0 moving up, containing line i+1 of the specified file.

  • I believe that some of those quotes can be dropped, nevertheless this works fine! – Aldebaran Feb 24 '16 at 13:30
  • The quotes are more a safety measure than a necessity when working with variables. But note, the script above assumes that you have equal or less lines of text than mail addresses. So if you have a text file that has more lines than your mail addresses, then you should work with $lines_in_addr in the while statement condition. – assefamaru Feb 24 '16 at 13:37
  • This is extremely inefficient as it reads both files N+1 times (where N is the number of lines - assuming the same number of lines for both files). – don_crissti Feb 24 '16 at 13:37
  • @don_crissti, I made an edit above to use arrays to store each files and work with the array instead of reading the file in every round of the loop. – assefamaru Feb 24 '16 at 14:30
  • That's better. There are other ways too, without "storing" the data (not even in arrays) but since the OP doesn't bother to post some input samples and specify if the two files have equal no. of lines (and what happens if that is not the case) I won't go into details. – don_crissti Feb 24 '16 at 15:40
message=$(head -n ${number} file_wit_TEXT | tail -1)
address=$(head -n ${number} file_with_ADDRESSES | tail -1)
echo ${message} | mail ${address}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.