Existem vários pontos de falha possíveis no seu script. Primeiro, rm *.old*
use globbing para criar uma lista de todos os arquivos correspondentes, e isso pode lidar com nomes de arquivos contendo espaços em branco. Seu script, no entanto, atribui uma variável a cada resultado da glob e faz isso sem citar. Isso será interrompido se os nomes dos arquivos contiverem espaços em branco. Por exemplo:
$ ls
'file name with spaces.old.txt' file.old.txt
$ rm *.old.* ## works: both files are deleted
$ touch "file.old.txt" "file name with spaces.old.txt"
$ for i in ./*; do oldfile=$i; rm -v $oldfile; done
rm: cannot remove './file': No such file or directory
rm: cannot remove 'name': No such file or directory
rm: cannot remove 'with': No such file or directory
rm: cannot remove 'spaces.old.txt': No such file or directory
removed './file.old.txt'
Como você pode ver, o loop falhou no arquivo com espaços em seu nome. Para fazer isso corretamente, você precisa citar a variável:
$ for i in ./*; do oldfile="$i"; rm -v "$oldfile"; done
removed './file name with spaces.old.txt'
removed './file.old.txt'
O mesmo problema se aplica a praticamente todos os usos do $i
seu script. Você deve sempre citar suas variáveis .
O próximo problema possível é que você espera que *.old.*
corresponda aos arquivos com a extensão .old
. Não faz. Corresponde a "0 ou mais caracteres" ( *
), depois a .
, "antigo", depois outro .
e depois a "0 ou mais caracteres novamente". Isso significa que não corresponderá a algo como file.old
, mas apenas algo como `file.old.foo:
$ ls
file.old file.old.foo
$ for i in *; do if [[ "$i" == *.old.* ]]; then echo $i; fi; done
file.old.foo
Então, não há rival file.old
. De qualquer forma, seu script é muito mais complexo do que o necessário. Experimente este:
#!/bin/bash
for i in *; do
if [[ -f "$i" ]]; then
if [[ "$i" == *.old ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i doesn't have an .old extension"
fi
cp -v "$i" "$i".old
else
echo "$i is not a file"
fi
done
Observe que eu adicionei -v
às instruções rm
e cp which does the same thing as what you were doing with your
echo`.
Isso não é perfeito, pois quando você descobrir, por exemplo, file.old
que será removido e, mais tarde, o script tentará copiá-lo e falhar, pois o arquivo não existe mais. No entanto, você não explicou o que seu script está realmente tentando fazer, então não posso consertar isso para você, a menos que você nos diga o que realmente está tentando realizar.
Se o que você deseja é: i) remover todos os arquivos com a .old
extensão e ii) adicionar a .old
extensão a qualquer arquivo existente que não o possua, tudo o que você realmente precisa é:
#!/bin/bash
for i in *.old; do
if [[ -f "$i" ]]; then
rm -v "$i" || echo "rm failed for $i"
else
echo "$i is not a file"
fi
done
## All the ,old files have been removed at this point
## copy the rest
for i in *; do
if [[ -f "$i" ]]; then
## the -v makes cp report copied files
cp -v "$i" "$i".old
fi
done
rm *.old.*
que remove esses arquivos. mas não o arquivo de backup file.old. Estou tentando fazer isso no meu script. ObrigadoOs únicos casos
rm $oldfile
poderia falhar é quando o nome do arquivo contém qualquer caráter deIFS
(espaço, tabulação, nova linha) ou qualquer personagem glob (*
,?
,[]
).Se algum caractere
IFS
estiver presente, o shell executará a divisão de palavras e com base na presença de caracteres brilhantes expansão do nome do caminho na expansão variável.Portanto, por exemplo, se o nome do arquivo for
foo bar.old.
, a variáveloldfile
conteráfoo bar.old.
.Quando você faz:
shell inicialmente divide a expansão do
oldfile
on space em duas palavras,foo
ebar.old.
. Então o comando se torna:o que obviamente levaria a resultados inesperados. By the way, se você tiver quaisquer operadores englobamento (
*
,?
,[]
) na expansão, em seguida, expansão de nome seria feito também.Você precisa citar as variáveis para obter o resultado desejado:
Agora, nenhuma divisão de palavras ou expansão de nome de caminho seria feita; portanto, você deve obter o resultado desejado, ou seja, o arquivo desejado será removido. Se algum nome de arquivo começar
-
, faça:Você pode perguntar por que não precisamos citar variáveis quando usadas internamente
[[
, o motivo[[
é umabash
palavra - chave e ela lida com a expansão de variáveis internamente, mantendo a expansão literal.Agora, alguns pontos:
Você deve redirecionar STDERR (
exec 2>errorfile
) antes dorm
comando[[ -s errorfile ]]
test, caso contrário , forneceria falsos positivosVocê usou
[ -s $errorfile ]
, está usando uma expansão de variável$errorfile
, que seria NUL, pois aerrorfile
variável não está definida em nenhum lugar. Talvez você quis dizer, apenas[ -s errorfile ]
, com base no redirecionamento STDERRSe a variável
errorfile
for definida, durante o uso[ -s $errorfile ]
, ela se engasgaria novamente com os casos acima mencionadosIFS
e globbing porque[[
, diferentemente ,[
não é tratada internamente porbash
Na parte posterior do script, você está tentando
cp
o arquivo já removido (novamente sem citar a variável); isso não faz sentido; verifique esse mandril e faça as correções necessárias com base no seu destino.fonte