não consegue descobrir o erro no operador inesperado do shell script

4

$ sh backup-to-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-efêmero: ~ $ 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
    
por Ashish Karpe 06.11.2015 / 18:38

4 respostas

6
  1. não use for para iterar as linhas de um arquivo, use

    while IFS= read -r line; do ...; done < filename
    
  2. você não precisa canalizar ls de saída para um arquivo, especialmente usando -F

  3. use o bash [[ x == y ]] para comparações de padrões e o padrão está do 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
    
por 06.11.2015 / 19:30
3

Mesmo que você esteja descarregando a saída de 'ls' em um arquivo e analisando que você está indiretamente analisando a saída de 'ls' que é problemática, uma idéia muito ruim ou ERRADA !!! dependendo de quem você pergunta.

Aqui está porque você não deve analisar a saída de 'ls' !

Aqui estão Nomes de arquivo e nomes de caminho 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 tenha escapado (colocando o prefixo com uma barra invertida ('\')), ele pode ser interpretado como um parâmetro.

Evitar analisar '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

Qual é o mesmo que

/bin/ls -alF | awk '{ print $9 }'

./
../
.bashrc
.forever/
BASH.Indirect.Reference.sh
array.dat
basharray.sh*
dont_parse_ls.sh

YMMV

    
por 06.11.2015 / 19:27
3

Existem pelo menos dois grandes problemas no script. Seu problema fundamental é o snippet:

if [ $filename* =

Existem alguns problemas com isso. Primeiro, no shell-scripting, você não pode "glob" um padrão de correspondência. Bem, você pode, mas se o arco da vassoura resultar em mais de uma correspondência, você receberá as duas, caso em que o programa "[" (sim, é um programa) tentará avaliar:

filename1 filename2 filename3 = $i

Funciona se e somente se o filglob 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 é o caso. Se "$ file *" se expande para nenhum arquivo, você pode (dependendo de uma configuração shopt) obter a string vazia:

= $i

que fará com que [ falhe. Com o shopt certo, você consegue:

backup-2014-whatever* = $i

Com o * sendo parte da comparação.

O segundo problema fundamental é o uso do parâmetro -F em ls . Isso diz ao ls para acrescentar ao nome do arquivo um dos vários caracteres, dependendo se o arquivo é um executável, um link flexível, etc.

O NetScr1be está em algo, 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 , que imprimirá apenas os nomes dos arquivos em uma única coluna, sem frescuras. (Para diretórios muito grandes, ele os classificará, e isso pode ser um problema, caso em que há uma opção no-sort; ou use find.)

Para ser mais seguro, suas variáveis devem ter aspas duplas, e tanto o LHS quanto o RHS são prefixados com um caractere fictício, para garantir que nomes de arquivos estranhos que começam com - não sejam descartados.

Eu usaria o conselho de Glenn, mais ou menos, e faria assim:

command ls -1 | while read file; do
    if [ x"$file" = x"$filename" ]]; then 
        echo Do Work Here
    fi
done

É assim que eu faria , mas Glenn gentilmente me informou, eu realmente deveria fazê-lo

:

for file in *; do 
    if [[ $file == $filename ]]; then ...
    
por 06.11.2015 / 19:45
1

Este script faz tudo. Por que não isso? O shell selecionará os arquivos corretos para você, portanto não é necessário 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 .
  • Não há if declarações.
  • O único ponto de decisão é o for loop.
  • Fácil de ler.
por 07.11.2015 / 00:30