디렉토리에서 일치하는 모든 파일을 이메일로 보내는 스크립트

디렉토리에서 일치하는 모든 파일을 이메일로 보내는 스크립트

데이터 파일을 자동으로 보내도록 bash 스크립트를 설정해 보세요. 원하는 최종 결과는 일주일에 한 번 지정된 디렉터리를 확인하고 지난 2일 동안 수정된 모든 Excel 파일을 나열하고 지정된 수신자 목록에 이메일을 보내는 것입니다.

Sendmail을 구성하고 실행 중입니다(Gmail 릴레이 사용). 구성하고 작동 중입니다. 일반적으로 보내려는 명령은 CLI에서 직접 보내면(첨부 파일이 포함된 메일 ​​보내기 및 받기) 작동하지만 스크립트에서 호출하려고 하면 반복적으로 실패합니다. 모든 것은 디렉토리와 파일 이름에 공백이 포함되어 있다는 사실에서 비롯된 것 같습니다. 나는 이것을 변경할 수 없습니다. 파일 이름 지정을 제어할 수 없습니다. 그러나 이것이 내 스크립트의 문제점인 것 같습니다.

두 가지 주요 질문:

  1. 모든 파일을 한 번에 보내려고 하면 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.xls3개의 값으로 처리됩니다. ( /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

파일을 개별적으로 보내려면 위의 마지막 두 줄 대신 다음을 시도했습니다.

# 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    

한 번에 한 장씩 우편으로 보내려면 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%는 루프 내부가 아닌 루프에서 변수를 꺼내는 방법에 관한 것입니다.)

관련 정보