
データファイルを自動的に送信するようにbashスクリプトを設定してみてください。必要な最終結果は、週に一度指定されたディレクトリを確認し、過去2日間に変更されたすべてのExcelファイルを一覧表示し、指定された受信者のリストに電子メールを送信することです。
Sendmailを設定して実行しています(Gmailリレーを使用)。設定して動作しています。通常送信するコマンドは、CLIから直接送信すると(添付ファイルを含むメールの送信と受信)機能しますが、スクリプトから呼び出そうとすると繰り返し失敗します。すべては、ディレクトリとファイル名にスペースが含まれているという事実から来ているようです。私はこれを変更することはできません。ファイルの命名を制御できません。しかし、これが私のスクリプトの問題のようです。
2つの主な質問:
- すべてのファイルを一度に送信しようとすると、muttは添付ファイルを添付できないことを報告します。
Can't stat "/path\ to/file1.xls
/path\ to/file2.xls": No such file or directory
改行文字は $FILES 変数の一部として渡されます。
- 一度に1つのファイルを送信するディレクトリを繰り返すと(一部のファイルがかなり大きいため、目的の結果)、スクリプトはスペースをエスケープするかどうかに関係なく区切り文字として解釈するため、
/path/to/the\ files/file\ 1.xls
3つの値として扱われます。 (/path/to/the\
、files/file\
、1.xls
)。
スクリプトの前半は実行されましたが(すべてのファイルを同時に転送)、ループを追加しようとしたときに中断されました。もちろん、以前の実行バージョンは保存されませんでした。正しい区切り文字を得るためにループを試してみましたが、set ifs=$'\n'
それを所定の位置に置くと、muttはファイルのフルパスがファイルではないか、指定された受信者がないことを伝えます。本当に怒っています。
スクリプト:
#!/bin/bash
# This file should send an email to specified recipients with data files for the week attached.
# Set reply-to address for Mutt
export REPLYTO="[email protected]"
# Replace with space separated email address of all recipients
EMAILS="[email protected] [email protected]"
# Get today's date for subject
# Date is in YYYY-MM-DD format
TODAY=$(date +%F)
# Set the message body
MBODY="Sending this week's data files.\n"
# Set the starting directory
# Don't bother escaping it, this is fixed in FILES variable below
DIR="/home/user/path to files"
# Get the list of files to send
FILES=$(find "$DIR" -type f -mtime -2 | sed 's/ /\\ /g' | grep ".xls")
# Check to see if we found any files or not
if [ -z "$FILES" ]; then
MBODY="No matching files added or modified within last 2 days. No files sent.\n"
echo "$MBODY" | mutt -s "Data files for $TODAY" $EMAILS
fi
# Send all files in a single email
echo $MBODY | mutt -s "Data files for $TODAY" -a "$FILES" -- $EMAILS
ファイルを個別に送信するには、上記の最後の2行の代わりに次のことを試しました。
# Cycle through FILES array and send each file individually
for datafile in ${FILES[*]}
do
set IFS=$'\n\t'
echo $MBODY | mutt -s \"Data files for $TODAY\" -a $datafile -- $EMAILS
unset $IFS
done
助けが必要ですか?私はこの問題についてしばらく詰まっていました。他の言語で使用する方が簡単な場合は、muttやbashを使用するのが好きではありません。
答え1
set "/home/user/path to files/"*.xls
for f do [ "$f" -nt "$two_day_old_file" ] && set "$@" "$f" ; shift ; done
touch "$two_day_old_file"
echo $MBODY | mutt -s "Data files for $TODAY" -a "$@" -- $EMAILS
一度に1枚ずつ郵送するには、次の行echo
を次のように変更してください。
for mailf do echo "$MBODY" |
mutt -s "Data files for $TODAY" -a "$mailf" -- $EMAILS
done
うまくいくかもしれませんが、実際の質問は次のとおりです。
...
set IFS=...
...
これは内部フィールド区切り文字の値にはまったく影響を与えず、代わりにその値をIFS=...
最初の位置引数またはに割り当てます$1
。$IFS
それでもあなたの前に来たすべてを大切にしてくださいset
$1
。あなたがしなければならないことは次のとおりです。
IFS='
'
または...
IFS=${IFS# }
...デフォルトに設定されている場合は実行可能なスクリプトで、スクリプトで他の項目を変更しない場合は、$IFS
デフォルト値を使用する必要があります。$IFS
答え2
問題は$FILE
配列ではありませんが、次のようにアクセスすることです。
for datafile in ${FILES[*]}
ただ巨大な文字列を返すので、すべてのファイルが一度に返されます。
この問題を解決するには、$FILE
ループ内の各ファイルに改行文字を追加します。これにより、echo -e
各行が個別に返されます。
# Get the list of files to send
FILES=$(find "$DIR" -type f -mtime -2 | sed 's/ /\\ /g' | grep ".xls" | sed '/.xls$/ a\\\n')
それから
for datafile in $(echo -e $FILES)
do
echo $MBODY | mutt -s \"Data files for $TODAY\" -a "$datafile" -- $EMAILS
done
また、二重引用符を追加すると、$datafile
ファイル名の空白の問題が解決されます。
答え3
作業方法が把握されたようです。$IFS
ディレクトリ全体のリストを文字列や配列として扱わないでください。見つかった各項目について処理します。最後のループを次に置き換えます。
find "$DIR" -type f -mtime -2 -name '*.xls*' -exec sh -c '
for file do
# Check to see if we found any files or not
if [ -z "$file" ]; then
echo "$NOBODY" | mutt -s "Data files for $TODAY" $EMAILS
# If we found files, then email them
else
echo "$MBODY" | mutt -s "Data files for $TODAY" -a "$file" -- $EMAILS
fi
done
' sh {} +
中には$NOBODY
、一致するファイルが見つからないという内容の他のメッセージ本文があります。"*.xlsx*"
.xlsファイルと.xlsxファイルの両方が一致することを確認するために使用されます。これは機能しますが、上記で宣言された変数はループに渡されません。export
各命令の前に命令を追加したところ、上記の命令が完了しました。 (変数をループに入れるよりエレガントな方法がある場合は、まだ見つかりませんでした。ループと変数の議論の99%は、ループ内ではなくループから変数を取り出す方法です。)