
$ sh backup-para-s3.sh
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
ubuntu@accretive-staging-32gb-ephemeral:~$ cat backup-to-s3.sh
#Script to move /home/ubuntu/backup folder to S3://auto-backup
#Author Ashish Karpe
cd /mnt/backup
filename="bkup_$(date +%Y%m%d_)"
/bin/ls -alF | awk '{ print $9 }' > /tmp/file
for i in $(cat /tmp/file); do
# echo $i;
# read a;
# echo $filename;
if [ $filename* = $i ]
then
echo "Copying " $i "to S3://auto-backup";
s3cmd put $i s3://auto-backup
fi
done
Responder1
não use
for
para iterar nas linhas de um arquivo, usewhile IFS= read -r line; do ...; done < filename
você não precisa canalizar
ls
a saída para um arquivo,especialmenteusando-F
- use bash
[[ x == y ]]
para comparações de padrões, e o padrão está no lado direito:
#!/bin/bash
cd /mnt/backup
prefix="bkup_$(date +%Y%m%d_)"
for file in * .*; do
[[ -f $file ]] || continue # skip things like directories and soft links
if [[ $file == $prefix* ]]; then
echo "Copying " $file "to S3://auto-backup";
s3cmd put $file s3://auto-backup
fi
done < /tmp/file
Responder2
Mesmo que você esteja despejando a saída de 'ls' em um arquivo e analisando, você está analisando indiretamente a saída de 'ls', o que é problemático, uma péssima ideia ou ERRADO!!! dependendo de quem você pergunta.
Aqui estápor que você não deve analisar a saída de 'ls'!
Aqui estáNomes de arquivos e caminhos no Shell: como fazer isso corretamente!
Por exemplo, se um dos arquivos tiver um '-' (traço/hífen) no nome do arquivo que não tem escape (prefixando-o com uma barra invertida ('\')), ele pode ser interpretado como um parâmetro.
Evitar a análise de 'ls' pode ser tão simples quanto;
find . -maxdepth 1 -iname "*"
.
./dont_parse_ls.sh
./array.dat
./.bashrc
./BASH.Indirect.Reference.sh
./basharray.sh
./.forever
O que sai igual a
/bin/ls -alF | awk '{ print $9 }'
./
../
.bashrc
.forever/
BASH.Indirect.Reference.sh
array.dat
basharray.sh*
dont_parse_ls.sh
YMMV
Responder3
Existem pelo menos dois problemas principais no script. Seu problema fundamental é o trecho:
if [ $filename* =
Existem alguns problemas com isso. Primeiro, em scripts de shell, você não pode "globar" um padrão de correspondência. Bem, você pode, mas se o fileglob resultar em mais de uma correspondência, você obterá os dois; nesse caso, o programa "[" (sim, é um programa) tentará avaliar:
filename1 filename2 filename3 = $i
Funciona se e somente se o fileglob se expandir para exatamente um nome de arquivo, e você raramente pode garantir isso. No seu caso, $filename se expande para pelo menos um arquivo, mas você deve estar ciente de que nem sempre é esse o caso. Se "$file*" se expandir para nenhum arquivo, você poderá (dependendo da configuração do shopt) obter a string vazia:
= $i
o que fará com que ele [
falhe. Com a loja certa, no entanto, você obtém:
backup-2014-whatever* = $i
Com o *
ser parte da comparação.
O segundo problema fundamental é o uso do -F
parâmetro em ls
. Isso diz ao ls para anexar ao nome do arquivo um dos vários caracteres, dependendo se o arquivo é um executável, um soft-link, etc.
NetScr1be está no caminho certo, mas veja, você não precisa seguir o conselho do NetScr1be e nunca usar ls
... apenas não use ls -l
. Em vez disso, use ls -1
which imprimirá apenas os nomes dos arquivos em uma única coluna, sem frescuras. (Para diretórios muito grandes, ele irá classificá-los, e isso pode ser um problema; nesse caso, há uma opção de não classificação; ou use find.)
Para ser mais seguro, suas variáveis devem estar entre aspas duplas e tanto LHS quanto RHS prefixados com um caractere fictício, para garantir que nomes de arquivos estranhos que começam com a -
não sejam confundidos.
Eu usaria o conselho de Glenn, mais ou menos, e faria desta forma:
command ls -1 | while read file; do
if [ x"$file" = x"$filename" ]]; then
echo Do Work Here
fi
done
Foi assim que euseriafazer isso, mas Glenn gentilmente me informou, eu realmente deveria fazer issodelecaminho:
for file in *; do
if [[ $file == $filename ]]; then ...
Responder4
Este script faz tudo. Por que não isso? O shell selecionará os arquivos corretos para você, portanto não há necessidade de chamar ls
:
#!/bin/sh
for file in /mnt/backup/bkup_$(date +%Y%m%d)_*
do
s3cmd put "$file" s3://auto-backup
done
- O único comando externo é
s3cmd
. - Sem
if
declarações. - O único ponto de decisão é o
for
loop. - Fácil de ler.