this bash one-liner is beyond me
Giorgos Keramidas
keramida at ceid.upatras.gr
Wed Jan 11 17:19:59 EET 2006
On 2006-01-11 16:53, "Nick Demou (enLogic)" <ndemou at enlogic.gr> wrote:
> στην σελίδα [1] βρήκα ένα bash one-liner το οποίο επιτρέπει σε ένα
> χρήστη να εκπαιδευει το spamassassin (κάνωντας move τα email που έχουν
> κακοχαρακτηριστεί ως spam ή ham σε δύο άλλους φακέλους -it_is_spam ,
> it_is_ham-). Φυσικά δεν δούλεψε :-) και ψάχνωντας κατέληξα σε αυτό το
> κομάτι της γραμμής το οποίο "χτυπάει" (όλα μια γραμμή):
>
> $/usr/bin/tee > \
> (/usr/bin/sa-learn --spam --single > /dev/null) \
> | /usr/bin/spamc | /usr/lib/cyrus-imapd/deliver Inbox
>
> αυτό που θεωρητικά θα έπρεπε να κάνει είναι να πάρει το stdin και να το
> προωθήσει αφενώς στην εντολή
> /usr/bin/sa-learn --spam --single > /dev/null
>
> και αφετέρου στην εντολή
> | /usr/bin/spamc | /usr/lib/cyrus-imapd/deliver Inbox
>
> αν το τρέξεις όμως το bash παραπωνιέται:
> bash: syntax error near unexpected token `('
>
> εγώ κατέθεσα τα όπλα (ίσως και να έχω κάψει νευρώνες βεβαιά[2]) - καμιά
> ιδέα?
Νευρώνες έχει κάψει ο καημένος που το έγραψε και πρέπει να τον χτυπήσεις
στο κεφάλι με printout από το Single UNIX Specification v.3, για να
μάθει να μη γράφει bash-specific μαλακίες και μάλιστα λάθος.
Το > redirection δεν κάνει αυτό που ελπίζει αυτός να κάνει, δηλαδή να
στείλει το output της tee ως stdin στην εντολή που υπάρχει ανάμεσα από
τα ( ... ). Στην προσπάθεια να αποφύγει να φτιάξει `temporary file'
κατέληξε σε μια μπούρδα και μισή.
Μια λύση, που όμως _χρησιμοποιεί_ temporary file, είναι μάλλον κάτι λίγο
πιο περίπλοκο, που μοιάζει με αυτό:
env TMPFILE=`mktemp /var/tmp/saXXXXXX` \
( [ -z "${TMPFILE}" ] && exit 1 ; cat > "${TMPFILE}" ;
{ /usr/bin/spamc "${TMPFILE}" ; spam=$? ; } | \
/usr/lib/cyrus-imapd/deliver Inbox ; \
type="spam" ; \
[ $spam -eq 0 ] && type="ham" ; \
/usr/bin/sa-learn --"$type" --single < "${TMPFILE}" >/dev/null 2>&1 ; \
/bin/rm -f "${TMPFILE}" )
Αν αυτό δεν έχει τον περιορισμό να είναι ``μια γραμμή'', μπορείς να το
κάνεις κανονικό script και να γράψεις πιο ξεκάθαρο κώδικα και να βάλεις
σε καίρια σημεία σχόλια σχετικά με τα βήματα που κάνεις:
#!/bin/sh
TMPDIR="${TMPDIR:-/var/tmp}"
TMPFILE=`mktemp "${TMPDIR}/saXXXXXX"`
if test $? -ne 0 || test -z "${TMPDIR}" ; then
echo 2>&1 "spam-filter [$$]: ${TMPDIR}: failed to create temporary file"
exit 75
fi
cat > "${TMPFILE}"
if test $? -ne 0 ; then
echo 2>&1 "spam-filter [$$]: ${TMPFILE}: cannot save message text"
exit 75
fi
# * NOTE: We run spamc in the current shell/process to be able
# to save $rc with its return code in the environment of the
# spam-filter process. Saving the return code of cyrus-imapd is
# not exactly what we want to do, since spamc may report a
# message as "ham", but failing to deliver it may trigger a
# "spam" result because of the failure reported by the entire
# pipe command.
{ /usr/bin/spamc "${TMPFILE}" ; spam=$? ; } | /usr/lib/cyrus-imapd/deliver Inbox
if test $? -ne 0 ; then
echo >&2 "spam-filter [$$]: ${TMPFILE}: failed to deliver message to cyrus imapd"
exit 75
fi
# Feed the message once more, to sa-learn, since we know the
# result of the checks by spamc by now.
if test $spam -eq 0 ; then
type="ham"
else
type="spam"
fi
/usr/bin/sa-learn --"$type" --single < "${TMPFILE}" > /dev/null 2>&1
# It's ok to ignore errors here. The worst that can happen is
# that sa-learn will learn slower.
/bin/rm -f "${TMPFILE}"
exit 0
More information about the Linux-greek-users
mailing list