O problema imediato em seu código é o erro de sintaxe na leitura da linha
if [' $x -eq 0 ']
O [
e ]
devem ser separados dos argumentos dentro de um caractere de espaço. Além disso, a substituição de comando nesta linha, '$x -eq 0'
, não faz sentido, pois tentaria executar o valor de $x
como um comando.
Você também tem problemas com a não-cotação de suas expansões de variáveis, o que desqualifica seu script de trabalhar em nomes de arquivos contendo caracteres em branco e padrões de globalização de nomes de arquivo.
O script também sobrecarrega incondicionalmente o arquivo newfile
desnecessariamente (e falharia se newfile
fosse o nome de um diretório existente) e não possui um #!
-line.
Não faz sentido perguntar ao usuário interativamente por caminhos de arquivo. Seria melhor para o usuário poder fazer uso do preenchimento do nome do arquivo do shell na linha de comando e fornecer os nomes dos arquivos para os arquivos como dois operandos:
$ ./script.sh some/path/file1 some/other/path/file2
Se o script for executado dessa maneira, os dois nomes de caminho estarão disponíveis no script como "$1"
e "$2"
.
O utilitário cmp
pode ser usado neste script sem criar um arquivo temporário . Em vez de redirecionar sua saída, deixe-a quieta usando sua opção -s
(para "silencioso") e use seu status de saída para determinar se os dois arquivos eram idênticos ou não.
O script seria parecido com
#!/bin/sh
if cmp -s -- "$1" "$2"; then
rm -i -- "$2"
fi
Ou mais curto,
#!/bin/sh
cmp -s -- "$1" "$2" && rm -i -- "$2"
Isso chamaria rm -i
no segundo dos dois nomes de caminho se ele se referisse a um arquivo com conteúdo idêntico ao primeiro nome de caminho. O --
nos comandos cmp
e rm
é necessário para evitar interpretar um nome de arquivo começando com um traço como um conjunto de opções.
O problema com este script, como com o seu próprio script, é que se você der a ele o mesmo nome de caminho duas vezes , ou seja, comparar um arquivo com ele mesmo, oferecerá para removê-lo.
Portanto, também precisamos ter certeza de que os dois caminhos se referem a dois arquivos diferentes .
Você pode fazer isso comparando as duas strings de nome de caminho entre si:
#!/bin/sh
if [ "$1" != "$2" ] && cmp -s -- "$1" "$2"; then
rm -i -- "$2"
fi
Isso pode ser suficiente para a maioria dos aplicativos, mas não leva em consideração links simbólicos. Em algumas shells você também pode usar o não-padrão -ef
test ("arquivo igual") que testa se dois nomes de caminho se referem ao mesmo arquivo (mesmo número de nó e dispositivo):
#!/bin/bash
if ! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2"; then
rm -i -- "$2"
fi
ou
#!/bin/bash
! [ "$1" -ef "$2" ] && cmp -s -- "$1" "$2" && rm -i -- "$2"
E com algumas verificações de integridade (também movendo o teste -ef
para a seção de verificações de sanidade):
#!/bin/bash
if [ "$#" -ne 2 ]; then
# did not get exactly two arguments
printf 'Usage:\n\t%s file1 file2\n' "$0" >&2
exit 1
elif [ ! -f "$1" ] || [ ! -f "$2" ]; then
echo 'One of the files does not exist (or is not a regular file)' >&2
exit 1
elif [ "$1" -ef "$2" ]; then
printf '%s and %s refer to the same file\n' "$1" "$2" >&2
exit 1
fi
cmp -s -- "$1" "$2" && rm -i -- "$2"
Note que citar as expansões de variáveis é importante, já que não é incomum que os nomes de caminho contenham espaços (no macOS, isso é muito comum). Duplicar as expansões de variáveis também os impede de serem interpretados como padrões de globalização de shell (seu código, por exemplo, não funciona em um arquivo chamado *
). Observe também o uso de uma linha #!
apropriada para o script.
Se o seu dever de casa requer que você leia os nomes dos caminhos dos dois arquivos interativamente, faça isso com read -r
e com IFS
definido como uma string vazia. Isso permitiria que você lesse nomes de caminho começando com caracteres de espaço em branco e contendo \
caracteres:
#!/bin/bash
IFS= read -p '1st pathname: ' -r p1
IFS= read -p '2nd pathname: ' -r p2
if [ ! -f "$p1" ] || [ ! -f "$p2" ]; then
echo 'One of the files does not exist (or is not a regular file)' >&2
exit 1
elif [ "$p1" -ef "$p2" ]; then
printf '%s and %s refer to the same file\n' "$p1" "$p2" >&2
exit 1
fi
cmp -s -- "$p1" "$p2" && rm -i -- "$p2"
Relacionados:
- Por que meu script de shell se sufoca em espaços em branco ou outros caracteres especiais?
- Noções básicas sobre "IFS = read -r line"
- ShellCheck.net
Se em algum momento você precisar verificar se um arquivo está vazio, como em seu próprio código, não chame wc
nele (ele é ineficiente, pois ele teria que ler o arquivo inteiro). Em vez disso, use um teste -s
:
if [ -s "$pathname" ]; then
printf '%s has non-zero size\n' "$pathname"
else
printf '%s is empty (or does not exist)\n' "$pathname"
fi
Veja man test
no seu sistema ou consulte o padrão POSIX para este utilitário .