Uma maneira possível de fazer isso
Um tempo atrás, criei uma função especificamente para esse propósito, que guardo no meu .bashrc
, e pode ser adaptada em um script. Você deve estar aproveitando os parâmetros posicionais para que os usuários possam colocar nomes de arquivos na linha de comando. Aqui está a minha função original:
swap_files() {
if [ $# -ne 2 ]
then
echo "Usage: swap_files file1 file2"
else
local TMPFILE=$(mktemp)
mv -- "" "$TMPFILE"
mv -- "" ""
mv -- "$TMPFILE" ""
fi
}
Você pode se livrar da declaração swap_files(){
, local
keyword e fechar }
e transformá-la em um script - basta adicionar #!/bin/bash
na parte superior. Concedido há toneladas de coisas que podem ser melhoradas, mas no nível muito básico que é quase tão simples quanto o swapping (que por sinal é freqüentemente ensinado em C para trocar itens de array, mas isso é apenas um tópico tangente).
#!/bin/bash
if [ $# -ne 2 ]
then
printf "Usage: swap_files file1 file2\n" > /dev/stderr
else
TMPFILE=$(mktemp)
mv -- "" "$TMPFILE"
mv -- "" ""
mv -- "$TMPFILE" ""
fi
Claro, lembre-se de citar os parâmetros posicionais se os nomes dos arquivos contiverem espaços. Assim:
swap_files 'file 1' 'file 2'
Anote o uso de --
para evitar problemas com nomes de arquivos que possuem -
neles. Uma maneira melhor seria adotar o hábito de referenciar arquivos no diretório de trabalho atual com ./
, especialmente se você estiver usando globstar *
(globstar não é relevante nesta questão, mas vale a pena mencionar se estamos falando de nomes de arquivos com os principais -
). Além disso, ./
way é mais portável, já que algumas versões de mv
, como , FreeBSD não tem a opção --
.
Como sugerido por terdon nos comentários, também podemos criar um arquivo temporário na pasta principal do primeiro arquivo para evitar a movimentação de arquivos nos sistemas de arquivos.
#!/bin/bash
if [ $# -ne 2 ]
then
printf "Usage: swap_files file1 file2\n" > /dev/stderr
else
file1_dir=${1%/*}
# just in case there were no slashes removed, assume cwd
if [ "$file1_dir" = "" ]; then
file1_dir="."
fi
tmpfile=$(mktemp -p "$file1_dir" )
mv -- "" "$tmpfile"
mv -- "" ""
mv -- "$tmpfile" ""
fi
Seu script e coisas para melhorar
1. Atribuição de variável redundante
file1=$file1
file2=$file2
Esta parte atribui a variável $file1
a ... file1
variable; há dois problemas com isso - atribuir variável a si mesmo é redundante e não existe para começar, não há nenhuma declaração dessa variável anteriormente no script.
2. Cuidado com divisão de palavras com leitura
Veja o que acontecerá se o usuário tentar colocar itens até mesmo entre aspas no comando read
:
$ read file1 file2
'one potato' 'two potato'
$ echo "$file1"
'one
$ echo "$file2"
potato' 'two potato'
De acordo com o comportamento do shell, o shell divide tudo que é lido em stdin
e tenta encaixar cada palavra nas variáveis correspondentes, e se as palavras excederem o número de variáveis - ele tenta empurrar tudo para a última variável. Eu recomendo que você leia em cada arquivo, um de cada vez.
3. Copiar para si mesmo é um erro
Você está fazendo
cp $file1 $file1;
Isso produzirá um erro
$ cp input.txt input.txt
cp: 'input.txt' and 'input.txt' are the same file
Talvez você quisesse fazer
cp "$file1" "$file1".tmp
Ou apenas use o comando mktemp
como eu fiz. Observe também a citação de variáveis para evitar a divisão de palavras.
Outras maneiras divertidas de fazer isso
Você sabia que pode filtrar qualquer arquivo com o redirecionamento para fazer uma cópia? Portanto, usar mv
ou cp
não é o único caminho. Algo parecido com isto:
$ cat ./wallpaper.jpg > wallpaper.jpg.tmp
$ cat ./screenshot.jpg > wallpaper.jpg
$ cat ./wallpaper.jpg.tmp > ./screenshot.jpg