Para uma tarefa, sou solicitado a escrever de forma inteligente uma função bash que possui a mesma funcionalidade básica que a função cp
(cópia). Ele só precisa copiar um arquivo para outro, portanto, nenhum arquivo múltiplo é copiado para um novo diretório.
Como eu sou novo no idioma bash, não consigo entender por que meu programa não está funcionando. A função original pede para substituir um arquivo, se ele já estiver presente, então tentei implementá-lo. Falha.
Parece que o arquivo falha em várias linhas, mas o mais importante é na condição em que verifica se o arquivo a ser copiado já existe ( [-e "$2"]
). Mesmo assim, ele ainda mostra a mensagem que deve ser acionada se essa condição for atendida (O nome do arquivo ...).
Alguém poderia me ajudar a corrigir esse arquivo, possivelmente fornecendo algumas informações úteis na minha compreensão básica do idioma? O código é o seguinte.
#!/bin/sh
echo "file variable: $2"
if [-e file]&> /dev/null
then
echo "The file name already exists, want to overwrite? (yes/no)"
read | tr "[A-Z]" "[a-z]"
if [$REPLY -eq "yes"] ; then
rm "$2"
echo $2 > "$2"
exit 0
else
exit 1
fi
else
cat $1 | $2
exit 0
fi
[ ... ] &> /dev/null
. Os testes suportados[ ... ]
são sempre silenciosos; é apenas no caso de erros de sintaxe que qualquer saída é produzida. Silenciar esse teste é simplesmente cavar sua própria cova.cat $1 | $2
"canaliza" a saída do primeiro comando para o comando na sua segunda variável. Mas esse é um nome de arquivo, não o nome de um comando a ser executado.[
comando no seuif
.|
e redirecionar para um arquivo com>
. Esses são problemas básicos de sintaxe que já deveriam ter sido abordados em sua classe.Respostas:
O
cp
utilitário substituirá alegremente o arquivo de destino se esse arquivo já existir, sem avisar o usuário.Uma função que implementa a
cp
capacidade básica , sem o uso,cp
seriaSe você deseja avisar o usuário antes de substituir o destino (observe que pode não ser desejável fazer isso se a função for chamada por um shell não interativo):
As mensagens de diagnóstico devem ir para o fluxo de erros padrão. É com isso que eu faço
printf ... >&2
.Observe que realmente não precisamos
rm
do arquivo de destino, pois o redirecionamento o truncará. Se se quiserrm
lo primeiro, então você teria que verificar se é um diretório, e se for, coloque o arquivo de destino dentro deste diretório em vez disso, apenas a forma comocp
faria. Isso é feito, mas ainda sem explícitorm
:Você também pode ter certeza de que a fonte realmente existe, o que é algo
cp
que faz (cat
também existe, portanto pode ser deixada de fora completamente, é claro, mas isso criaria um arquivo de destino vazio):Esta função não usa "bashismos" e deve funcionar em
sh
conchas de todos os tipos.Com um pouco mais de ajustes para oferecer suporte a vários arquivos de origem e um
-i
sinalizador que ativa o prompt interativo ao substituir um arquivo existente:Seu código tem espaçamentos incorretos
if [ ... ]
(precisa de espaço antes e depois[
e antes]
). Você também não deve tentar redirecionar o teste,/dev/null
pois o teste em si não possui saída. Além disso, o primeiro teste deve usar o parâmetro posicional$2
, não a stringfile
.Usando
case ... esac
como eu fiz, você evita ter que minúsculas / maiúsculas a resposta do usuário usandotr
. Embash
, se você queria fazer isso de qualquer maneira, uma maneira mais barata de fazê-lo teria sido a utilizaçãoREPLY="${REPLY^^}"
(para maiúscula) ouREPLY="${REPLY,,}"
(para lowercasing).Se o usuário disser "sim", com o seu código, a função colocará o nome do arquivo do arquivo de destino no arquivo de destino. Esta não é uma cópia do arquivo de origem. Ele deve passar para o bit de cópia real da função.
O bit de cópia é algo que você implementou usando um pipeline. Um pipeline é usado para passar dados da saída de um comando para a entrada de outro comando. Isso não é algo que precisamos fazer aqui. Simplesmente invoque
cat
o arquivo de origem e redirecione sua saída para o arquivo de destino.A mesma coisa está errada com você ligando
tr
antes.read
definirá o valor de uma variável, mas não produzirá saída; portanto, a canalizaçãoread
para qualquer coisa é absurda.Nenhuma saída explícita é necessária, a menos que o usuário diga "não" (ou a função se depara com alguma condição de erro como nos bits do meu código, mas como é uma função que eu uso em
return
vez deexit
).Você também disse "função", mas sua implementação é um script.
Dê uma olhada em https://www.shellcheck.net/ , é uma boa ferramenta para identificar bits problemáticos de scripts de shell.
O uso
cat
é apenas uma maneira de copiar o conteúdo de um arquivo. Outras maneiras incluemdd if="$1" of="$2" 2>/dev/null
sed "" "$1" >"2"
ouawk '1' "$1" >"$2"
outr '.' '.' <"$1" >"$2"
etc.A parte complicada é fazer com que a função copie os metadados (propriedade e permissões) da origem para o destino.
Outra coisa a notar é que a função que eu escrevi se comportará de maneira bem diferente de
cp
se o destino for algo como,/dev/tty
por exemplo (um arquivo não regular).fonte
cat "$1" >"$2"
funcionará em 2 vezes: o shell primeiro vê> "$2"
, o que significa: create-or-clobber (= empty) o arquivo "$ 2" e redireciona o stdout do comando para esse arquivo. Em seguida, ele lança o comandocat "$1"
:, e redireciona seu stdout para o arquivo"$2"
(já esvaziado ou criado vazio).-ef
comparações de arquivos elocal -a
.-ef
observa se os dois arquivos são iguais (também cuida dos links) elocal -a
cria uma variável de matriz local.