Newsgroup: it.comp.os.linux.sys
Titolo: Bash script, problema con escaping

Ho scritto questo semplice script di shell per fare il backup delle mie
caselle di posta:
--8<--
#!/bin/bash
# Directories
MAILDIR="/var/mail"
WORKDIR=$HOME
# List of mailboxes
HOME_MAILBOX_LIST=`cat ~/.mailboxlist`
MAILBOX_LIST=`ls $MAILDIR`
# Timestamp for archive name
TODAY=`date +%Y-%m-%d`
# The name of archive to be created
OUTFILE="${HOSTNAME}_mail-backup_$TODAY.zip"
# Create the list of files with full path to give as input to zip
LIST=""
for FILE in $MAILBOX_LIST
do
  LIST="$LIST $MAILDIR/$FILE"
done
for FILE in $HOME_MAILBOX_LIST
do
  LIST="$LIST $HOME/$FILE"
done
# Move to workdir
cd $WORKDIR
# Create a zip archive and move to backups dir
zip $OUTFILE $LIST
mv $OUTFILE /dir/to/backup/
# Exit
exit
--8<--
Il file .mailboxlist ha una struttura simile:
--8<--
Trash
Junk
Sent
mail/drafts
mail/notifiche ricevute
INBOX
Posta inviata
Bozze
--8<--
Tuttavia non funziona per il seguente motivo: ottenendo il contenuto del
file .mailboxlist con cat e iterando con FOR..IN vengono splittati i nomi
delle directory contenenti spazi.
Quotare i nomi delle directory con ls --quoting-style=... non serve perche'
comunque devo poi premettere il percorso completo, fare l'escape degli
spazi neppure perche' FOR..IN comunque li separa.
Ho provato a scrivere uno script sed ma non ho concluso granche' -- per
dire un eufemismo la curva di apprendimento di sed e' parecchio ripida.
Credo di trovarmi in un vicolo cieco. Come potrei risolvere?
Grazie anticipatamente
-- 
"We're just two lost souls swimming in a fish bowl -
year after year"

 Grazie anticipatamente
quello che tu vuoi fare con sed o awk e' circa questo:
echo a b | sed -e s/^/\"/ -e s/$/\"/
echo a b d n n m| awk -F "\n" '{printf "\""; printf $1; print "\""}'
puoi farlo sicuramente.
p.s.: Senti, non usare zip in Linux/UNIX.
Non e' che sia vietato, ma prendila come abitudine, soprattutto perche'
'zip' non e' installato su tutti gli unix e anche perche' 'zip' non e'
nativo di unix. Usa tar + gz o tar + bz. E in fin dei conti zip non credo
sia nemmeno GPL.
-- 
echo onailimissaM | awk 'BEGIN { FS = "" }
{ for (i = NF; i >= 1; i-- )
  printf $i }'; echo

 echo a b d n n m| awk -F "\n" '{printf "\""; printf $1; print "\""}'
mmmhhh usa sempre il printf, altrimenti ti inserisca la new-line.
echo a b d n n m| awk -F "\n" '{printf "\""; printf $1; printf "\""}'


 ... Come potrei risolvere?
Studiando un tutorial sulla bash.

 sia nemmeno GPL.
beh a dirla tutta non sono su linux, ma su cygwin; uso zip
esclusivamente per abitudine (anche se bzip dovrebbe, se non erro, dare
prestazioni migliori nella compressione)
-- 
Non si fo credito

 Studiando un tutorial sulla bash.
non lo escludo, caro il mio himmelman; cosa che faro' sicuramente.
P.S: e' un bel po' che sono assente dai gruppi it.compl.os.linux*, e'
sempre un piacere rileggere risposte spocchiose :)


 prestazioni migliori nella compressione)
beh .... "prestazioni" nel senso stretto direi di no :) E' avidissimo di
risorse.
diciamo che da "risultati migliori" per quanto riguarda i rapporti
di compressione.


 e le espressioni regolari in un quarto d'ora.
adesso non esageriamo :) ... diciamo che rispetto a certi algoritmi di
programmazione e' pure facile.


 di compressione.
intendevo dire questo :)


 echo a b d n n m| awk -F "\n" '{printf "\""; printf $1; printf "\""}'
awk mi sembra molto piu' immediato, anzi approfitto per ringraziarti
che' prendendo spunto dal tuo suggerimento ho scritto uno script per
automatizzare la localizzazione dei Nib
# for every language
for LANG in `cat $PROJECT_DIR/Localizations`
do
  # for every Nib file in English.lproj
  for NIB in `ls -d $PROJECT_DIR/English.lproj/*.nib`
  do
    # copy to language folder
    cp -nR $NIB $PROJECT_DIR/$LANG.lproj/
    # get Nib name
    NIB_NAME=`echo $NIB | awk 'BEGIN { FS = "/|.nib" } \
       { printf $(NF-1) }' -`
    # move to language folder
    cd $PROJECT_DIR/$LANG.lproj
    # localize the file
    nibtool -w _$NIB_NAME.nib -d $NIB_NAME.strings $NIB_NAME.nib
    # remove old Nib
    rm -rf $NIB_NAME.nib
    # rename new Nib
    mv _$NIB_NAME.nib $NIB_NAME.nib
  done
done


 e le espressioni regolari in un quarto d'ora.
Ok "studente medio". Leggiti doc. ed esempi 
http://sed.sourceforge.net/
 
...e fra un quarto d'ora... alla lavagna.
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

 delle directory contenenti spazi.
Considerazioni a parte su altri metodi, prova la differenza tra i due 
semplici script sotto in bash. Se ho capito bene, il secondo mi pare 
possa risolvere il tuo problema con gli spazi.
# --- script 1 -------------------------
DIRS="Trash
Junk
Sent
mail/drafts
mail/notifiche ricevute
INBOX
Posta inviata
Bozze"
for d in $DIRS; do
         echo "- $d -"
done
# ---script 2 --------------------------
DIRS="Trash
Junk
Sent
mail/drafts
mail/notifiche ricevute
INBOX
Posta inviata
Bozze"
IFS=$'\n' # di default la var. IFS e' impostata a $' \t\n'
for d in $DIRS; do
         echo "- $d -"
done
# -------------------------------------
Ciao


 done
wow, proprio quello che mi serviva!
come si dice, "that did the trick" ;)
Grazie mille


 IFS=$'\n' # di default la var. IFS e' impostata a $' \t\n'
Ho modificato lo script in questo modo:
- uso tar+gzip per la compressione
- uso un file temporaneo di appoggio per tar -T anziche' passare
l'interminabile teoria dei file sulla commandline
Sono giunto quindi a questo script:
#!/bin/bash
# Timestamp for archive name
today=`date +%Y-%m-%d`
# Move to workdir
cd $HOME
# The name of archive to be created
outfile="${HOSTNAME}_mail-backup_$today.tar.gz"
# Set IFS to ignore spaces in filenames
saved_ifs=$IFS
IFS=$'\n'
# Create the list of files with full path to give as input to tar
for f in `ls /var/mail`
do
  if [ -e .mailbackuplist ]
  then
    echo /var/mail/$f >> .mailbackuplist
  else
    echo /var/mail/$f > .mailbackuplist
  fi
done
for f in `cat ~/.mailboxlist`
do
  if [ -e .mailbackuplist ]
  then
    echo $HOME/$f >> .mailbackuplist
  else
    echo $HOME/$f > .mailbackuplist
  fi
done
# Restore IFS
IFS=$saved_ifs
# Create a tgz archive and move to backups dir
tar --ignore-failed-read --no-unquote -T .mailbackuplist -czf $outfile
mv $outfile /path/to/backup/
# Delete temp maliboxes list
rm .mailbackuplist
# Exit
exit
Leggo tuttavia che viene sconsigliato modificare il valore di IFS (e lo
credo bene), oppure di farlo per il piu' breve tempo possibile.
Non mi resta che capire come sospendere un servizio Windows durante il
backup (ma qua andiamo OT) e aggiungere lo script a cron per avere un
discreto sistema di backup della posta.


 IFS=$saved_ifs
lo dice sempre il "manuale del buon programmatore" :-)


 .mailbackuplist
ls -1 /var/mail | while read file
do
    echo "$file" >> .mailbackuplist
done
cat ~/.mailboxlist | while read file
do
    echo $HOME/$file >> .mailbackuplist
done
---------------------------------------------------------------------
Ti risparmi di cambiare IFS e anche due if con test di esistenza del
file in due cicli for.
-- 
Flavio Visentin
Membro del CICAP
Comitato Italiano per il Controllo delle Affermazioni di P4


a proposito .... ho appena scoperto l'esistenza di pbzip2 (parallel
bzip2)... che purtroppo e' ancora in beta. Domani lo provo sul quadri-xeon
... poiche' mi ero accorto che bzip lavorava solo su una CPU (sperando che
questo non si ciucci tutte le cpu :)


 file in due cicli for.
ommamma, troppo gentile; ci gioco un po' per capire cosa fa esattamente


 
Ci siano molti modi per raggiungere questo risultato in bash.
A parte la "read" che hai suggerito, mi vengono in mente anche questi 
(piu' o meno "fantasiosi") al posto del primo ciclo for:
# ls -1 /var/mail |sed -r 's/^(.+)$/\/var\/mail\/\1/' >> .mailbackuplist
# ls -1 /var/mail |awk '{ print "/var/mail/"$0 }' >> .mailbackuplist
# ls -1 /var/mail |perl -n -e 'print "/var/mail/$_"' >> .mailbackuplist
# find /var/mail/* -maxdepth 0 >> .mailbackuplist
...ma che (a parte l'ultimo) si possono adattare anche al secondo ciclo for.
Il suggerimento si basava sul "modo" che aveva adottato originariamente 
Claudio.
PS: Si', ok, scomodare perl o awk per un semplice problemino... :-)


 questo azzera il file giusto? :/
sě


 (piu' o meno "fantasiosi") al posto del primo ciclo for:
In effetti mi sono accorto che esiste un metodo ancora migliore per il
primo ciclo for:
ls -1 /var/mail > .mailbackuplist


 ls -1 /var/mail > .mailbackuplist
mmh, nope. Mi serve il path completo :(


 .mailbackuplist
ls -1 /var/mail | while read file
do
  echo /var/mail/$file >> .mailbackuplist
done
cat ~/.mailboxlist | while read file
do
   echo $HOME/$file >> .mailbackuplist
done
grazie ad entrambi


 mmh, nope. Mi serve il path completo :(
ls -1d /var/mail/* > .mailbackuplist
meglio? :-)


 meglio? :-)
ottimo!! opzione -d di ls, al volo non me la ricordavo...
(spero che Claudio si stia divertendo a vederci giocare :-) )


 (spero che Claudio si stia divertendo a vederci giocare :-) )
tra un po' mi metto il cappello con le orecchie d'asino ^^;;;
