È possibile scambiare due file in bash?Il modo più semplice per scambiare due file in bash
Oppure, possono essere scambiati in modo più breve di questo:
cp old tmp
cp curr old
cp tmp curr
rm tmp
È possibile scambiare due file in bash?Il modo più semplice per scambiare due file in bash
Oppure, possono essere scambiati in modo più breve di questo:
cp old tmp
cp curr old
cp tmp curr
rm tmp
Aggiungi questo al vostro .bashrc:
function swap()
{
local TMPFILE=tmp.$$
mv "$1" $TMPFILE
mv "$2" "$1"
mv $TMPFILE "$2"
}
Se si desidera gestire il potenziale fallimento di intermedi mv
operazioni, controllare Can Bal's answer.
Si prega di notare che né questa né altre risposte forniscono una soluzione atomica, perché è impossibile implementarle utilizzando syscalls Linux e/o popolari filesystem Linux. Per il kernel Darwin, selezionare exchangedata
syscall.
se mv "$ 2" "$ 1" non riesce, come si rileva e si esegue il rollback? –
@ Michael: Se sei preoccupato di questo, allora hai delle opzioni. È possibile stampare il nome del file temporaneo nell'operazione in modo che sia possibile copiarlo da soli. O potresti anche creare un file .backup di entrambi nella directory. Hai opzioni. –
Se si sta creando il file temporaneo nella stessa directory del file sorgente, si può usare 'ln' invece di' mv'. Per esempio 'ln" $ 1 "" $ tmp "; mv -f "$ 2" "$ 1"; mv "$ tmp" "$ 2" 'in questo modo se devi eseguire il rollback tutto ciò che devi fare è eliminare il file temporaneo, che è solo un collegamento a' $ 1'. Tuttavia non funzionerà per le directory (non è in grado di collegarle in modo fisso). – Haravikk
$ mv old tmp && mv curr old && mv tmp curr
è leggermente più efficiente!
avvolti in funzione di shell riutilizzabile:
function swap()
{
local TMPFILE=tmp.$$
mv "$1" $TMPFILE && mv "$2" "$1" && mv $TMPFILE $2
}
... e non 'mv' i tuoi file nel nirvana, se c'è un problema con' tmp'. +1 – Boldewyn
mv old tmp
mv curr old
mv tmp curr
Si potrebbe semplicemente spostarli, invece di fare una copia.
#!/bin/sh
# Created by Wojtek Jamrozy (www.wojtekrj.net)
mv $1 cop_$1
mv $2 $1
mv cop_$1 $2
http://www.wojtekrj.net/2008/08/bash-script-to-swap-contents-of-files/
usando mv significa avere uno operazioni di meno, non c'è bisogno per la RM finale, anche mv sta solo cambiando le voci di directory in modo che non si utilizza lo spazio su disco aggiuntivo per la copia.
Temptationh è quindi per implementare una funzione di shell swap() o alcuni di questi. Se fai estrema attenzione a controllare i codici di errore. Potrebbe essere terribilmente distruttivo. Inoltre, è necessario verificare la presenza di file tmp preesistenti.
in realtà vuoi scambiarli? penso che la sua pena ricordare che si può file sovrascritto il backup automaticamente con mv:
mv new old -b
si otterrà:
old and old~
se si desidera avere
old and old.old
puoi usare -S per cambiare ~ al suffisso personalizzato
mv new old -b -S .old
ls
old old.old
utilizzando questo approccio si può effettivamente scambiare più veloci, utilizzando solo 2 mv:
mv new old -b && mv old~ new
Sembrava promettente ma purtroppo l'opzione '-b' non è disponibile su OS X Lion – bloudermilk
Combinando le risposte migliori, ho messo nel mio ~ /.bashrc:
function swap()
{
tmpfile=$(mktemp $(dirname "$1")/XXXXXX)
mv "$1" "$tmpfile" && mv "$2" "$1" && mv "$tmpfile" "$2"
}
L'idea di Hardy era abbastanza buona per me. Quindi ho provato i miei seguenti due file per scambiare "sendsms.properties", "sendsms.properties.swap". Ma una volta chiamata questa funzione come stesso argomento "sendsms.properties", questo file è stato cancellato. Evitare a questo tipo di FAIL ho aggiunto qualche linea per me :-)
function swp2file()
{ if [ $1 != $2 ] ; then
local TMPFILE=tmp.$$
mv "$1" $TMPFILE
mv "$2" "$1"
mv $TMPFILE "$2"
else
echo "swap requires 2 different filename"
fi
}
Grazie ancora Hardy ;-)
Un problema che ho avuto quando utilizzando una delle soluzioni fornite qui: nomi di file otterrà acceso.
Ho incorporato l'uso di basename
e dirname
per mantenere intatti i nomi dei file *.
swap() {
if (($# == 2)); then
mv "$1" /tmp/
mv "$2" "`dirname $1`"
mv "/tmp/`basename $1`" "`dirname $2`"
else
echo "Usage: swap <file1> <file2>"
return 1
fi
}
Ho provato questo in bash e zsh.
* Quindi, per chiarire come questo è meglio:
Se si inizia con:
dir1/file2: this is file2
dir2/file1: this is file1
Le altre soluzioni finirebbe con:
dir1/file2: this is file1
dir2/file1: this is file2
I contenuti vengono scambiati ma i nomi dei file sono rimasto. La mia soluzione rende:
dir1/file1: this is file1
dir2/file2: this is file2
I contenuti e le nomi sono scambiati.
Nice .. Ma non funziona se i file si trovano nella stessa directory .. (Suppongo, in quel caso, l'unica cosa che ha senso è quello di scambiare il contenuto dei file, ma mantenere i nomi dei file :)) –
@ HåkonHægland dovrebbe funzionare se sono nella stessa directory.L'unica avvertenza è se sono entrambi in/tmp, nel qual caso puoi semplicemente cambiare lo script per spostarli in/tmp/foo o qualcosa del genere –
Una versione un po 'indurito che funziona per entrambi i file e le directory:
function swap()
{
if [ ! -z "$2" ] && [ -e "$1" ] && [ -e "$2" ] && ! [ "$1" -ef "$2" ] && (([ -f "$1" ] && [ -f "$2" ]) || ([ -d "$1" ] && [ -d "$2" ])) ; then
tmp=$(mktemp -d $(dirname "$1")/XXXXXX)
mv "$1" "$tmp" && mv "$2" "$1" && mv "$tmp"/"$1" "$2"
rmdir "$tmp"
else
echo "Usage: swap file1 file2 or swap dir1 dir2"
fi
}
Questo funziona su Linux. Non sono sicuro di OS X.
Non funziona su OSX/macOS. – raskhadafi
Ho questo in uno script di lavoro che ho consegnato. E 'scritto come una funzione, ma si sarebbe invocarlo
d_swap lfile rfile
La mv GNU ha la -b e l'interruttore -T. Puoi gestire le directory utilizzando l'opzione -T .
Le virgolette sono per nomi di file con spazi.
È un po 'prolisso, ma l'ho usato molte volte con file e directory. Ci possono essere casi in cui si vorrebbe rinominare un file con il nome di una directory, ma questo non è gestito da questa funzione.
Questo non è molto efficiente se tutto ciò che si vuole fare è rinominare i file (lasciandoli dove sono), meglio fare con una variabile di shell.
d_swap() {
test $# -eq 2 || return 2
test -e "$1" || return 3
test -e "$2" || return 3
if [ -f "$1" -a -f "$2" ]
then
mv -b "$1" "$2" && mv "$2"~ "$1"
return 0
fi
if [ -d "$1" -a -d "$2" ]
then
mv -T -b "$1" "$2" && mv -T "$2"~ "$1"
return 0
fi
return 4
}
Questa funzione consente di rinominare i file. Usa un nome temporaneo (mette un punto ').'di fronte al nome) nel caso in cui i file/le directory si trovino nella stessa directory, che di solito è il caso.
d_swapnames() {
test $# -eq 2 || return 2
test -e "$1" || return 3
test -e "$2" || return 3
local lname="$(basename "$1")"
local rname="$(basename "$2")"
(cd "$(dirname "$1")" && mv -T "$lname" ".${rname}") && \
(cd "$(dirname "$2")" && mv -T "$rname" "$lname") && \
(cd "$(dirname "$1")" && mv -T ".${rname}" "$rname")
}
Questo è molto più veloce (non c'è copia, basta rinominare). È ancora più brutto. E rinominerà qualsiasi cosa: file, directory, pipe, dispositivi.
Questo è quello che uso come comando sul mio sistema ($HOME/bin/swapfiles
). Penso che sia relativamente resistente alla cattiveria.
#!/bin/bash
if [ "$#" -ne 2 ]; then
me=`basename $0`
echo "Syntax: $me <FILE 1> <FILE 2>"
exit -1
fi
if [ ! -f $1 ]; then
echo "File '$1' does not exist!"
fi
if [ ! -f $2 ]; then
echo "File '$2' does not exist!"
fi
if [[ ! -f $1 || ! -f $2 ]]; then
exit -1
fi
tmpfile=$(mktemp $(dirname "$1")/XXXXXX)
if [ ! -f $tmpfile ]; then
echo "Could not create temporary intermediate file!"
exit -1
fi
# move files taking into account if mv fails
mv "$1" "$tmpfile" && mv "$2" "$1" && mv "$tmpfile" "$2"
Ecco uno script swap
con l'errore paranoico controllo per evitare caso improbabile di un guasto.
Script:
#!/bin/sh
if [ -z "$1" ] || [ -z "$2" ]; then
echo "Expected 2 file arguments, abort!"
exit 1
fi
if [ ! -z "$3" ]; then
echo "Expected 2 file arguments but found a 3rd, abort!"
exit 1
fi
if [ ! -f "$1" ]; then
echo "File '$1' not found, abort!"
exit 1
fi
if [ ! -f "$2" ]; then
echo "File '$2' not found, abort!"
exit 1
fi
# avoid moving between drives
tmp=$(mktemp --tmpdir=$(dirname $1))
if [ $? -ne 0 ]; then
echo "Failed to create temp file, abort!"
exit 1
fi
# Exit on error,
mv $1 $tmp
if [ $? -ne 0 ]; then
echo "Failed to to first file '$1', abort!"
rm $tmp
exit 1
fi
mv $2 $1
if [ $? -ne 0 ]; then
echo "Failed to move first file '$2', abort!"
# restore state
mv $tmp $1
if [ $? -ne 0 ]; then
echo "Failed to move file, (unable to restore) '$1' has been left at '$tmp'!"
fi
exit 1
fi
mv $tmp $2
if [ $? -ne 0 ]; then
# this is very unlikely!
echo "Failed to move file, (unable to restore) '$1' has been left at '$tmp', '$2' as '$1'!"
exit 1
fi
cp sarà davvero lento rispetto a mv soprattutto per i file di grandi dimensioni, si replica inutilmente i dati – jbat100