0

I am looking for Unix script where I can attach multiple files having similar name.

For e.g, on server I am having followings files:

output2019_1.txt
output2019_2.txt
output2019_3.txt
output2020_1.txt

echo "Hello" | mailx -a "test attachments" -a output2019* abc@gamil.com

Above script only attaching one file of 2019. I want all 3 files with 2019 should attach to email.

Please I am looking for actual attachment not some uuencode where it past on email body.

αғsнιη
  • 41,407
Gujju
  • 1
  • Firstly that needs to be -A, not -a. Secondly mailx doesn't support that - you'll need to write a wrapper. – tink Aug 27 '22 at 03:40

2 Answers2

0

You can use brace-expansion in this way:

echo "Hello" | mailx -a "test attachments" '-aoutput2019_'{1..3}.txt abc@gamil.com
αғsнιη
  • 41,407
  • Thanks but none of them working: echo Hello | mailx $(printf -- '-A %s ' output2019*) abc@gamil.com Giving Following error: Account output201901_1.txt does not exist

    echo "Hello" | mailx -a "test attachments" '-aoutput2019_'{1..3}.txt abc@gamil.com Giving Following error: test attachments: No such file or directory

    – Gujju Aug 27 '22 at 13:50
  • @Gujju error related to my answer is telling that file "test attachments" doesn't exist which mailx command is trying to find and attach it to the mail but it finds no such file there. – αғsнιη Aug 27 '22 at 14:25
0

You can use printf and command substitution:

echo Hello | mailx $(printf -- '-A %s ' output2019*) abc@gamil.com

The -- tells printf that there are no more option arguments (otherwise it will complain about -A being an invalid option). The '-A %s ' is the format string, every remaining argument (the files matching output2019*.txt) will be printed using that format. e.g. mailx would be run as:

mailx -A output2019_1.txt -A output2019_2.txt -A output2019_3.txt abc@gamil.com

Note: this won't work with all filenames - it will fail with filenames containing whitespace or shell metacharacters. To cope with those, you can embed quotes in your format string. e.g.

echo Hello | mailx $(printf -- "-A '%s' " output2019*) abc@gamil.com

This will work with filenames that contain any characters except single-quotes.


To work with filenames containing ANY valid character, you'd have to first create an array containing multiple pairs of -A options and filenames. e.g. using process substitution in bash:

mapfile -d '' -t attachments < \
  <(find . -maxdepth 1 -name 'output2019*' -printf '-A\0%p\0')

echo Hello | mailx "${attachments[@]}" abc@gamil.com

When bash expands an array like this (i.e. in double-quotes, with [@] as the index), each element of the array is treated as a separate "word", and is not subject to any further word splitting or interpretation.

This requires GNU find (standard on Linux) for the -printf option. Here we're telling find to output, for each filename, -A, a NUL, then the filename followed by another NUL.

The mapfile command populates an array from stdin, and we're telling it that NUL is the separator character (with -d '')...and stdin is redirected (<) from find ... via process substitution. See help mapfile in bash. BTW, readarray is a synonym for mapfile in bash.

With the filenames in your example, this would populate the array $attachments with 6 elements:

$ declare -p attachments
declare -a attachments=([0]="-A" [1]="./output2019_1.txt" [2]="-A" [3]="./output2019_3.txt" [4]="-A" [5]="./output2019_2.txt")

IMO, this is the best version as it will work with any filenames. It's a little more typing, but it's worth it. It's always better to write scripts (and one-liners) defensively, always keeping "what could go wrong?" in mind and making sure that it won't.

cas
  • 78,579