Können zwei Dateien in bash getauscht werden?
Oder können sie auf kürzere Weise ausgetauscht werden:
cp old tmp
cp curr old
cp tmp curr
rm tmp
Fügen Sie dies zu Ihrem .bashrc hinzu:
function swap()
{
local TMPFILE=tmp.$$
mv "$1" $TMPFILE
mv "$2" "$1"
mv $TMPFILE "$2"
}
Wenn Sie einen potenziellen Ausfall von mv
-Vorgängen abarbeiten möchten, überprüfen Sie Can Bal's answer .
Bitte beachten Sie, dass weder diese noch andere Antworten eine atomic - Lösung bieten, da dies nicht unter Verwendung von Linux-Syscalls und/oder gängigen Linux-Dateisystemen implementiert werden kann. Aktivieren Sie für den Darwin-Kernel exchangedata
syscall.
$ mv old tmp && mv curr old && mv tmp curr
ist etwas effizienter!
In wiederverwendbare Shell-Funktion verpackt:
function swap()
{
local TMPFILE=tmp.$$
mv "$1" $TMPFILE && mv "$2" "$1" && mv $TMPFILE "$2"
}
tmpfile=$(mktemp $(dirname "$file1")/XXXXXX)
mv "$file1" "$tmpfile"
mv "$file2" "$file1"
mv "$tmpfile" "$file2"
möchten Sie sie tatsächlich austauschen? Ich denke, es ist erwähnenswert, dass Sie die überschriebene Datei automatisch mit mv sichern können:
mv new old -b
du wirst kriegen:
old and old~
wenn du möchtest
old and old.old
sie können -S verwenden, um ~ in Ihr benutzerdefiniertes Suffix zu ändern
mv new old -b -S .old
ls
old old.old
mit diesem Ansatz können Sie sie tatsächlich schneller austauschen, indem Sie nur 2 mv verwenden:
mv new old -b && mv old~ new
Ich kombiniere die besten Antworten und gebe dies in meine ~/.bashrc
function swap()
{
tmpfile=$(mktemp $(dirname "$1")/XXXXXX)
mv "$1" "$tmpfile" && mv "$2" "$1" && mv "$tmpfile" "$2"
}
Sie können sie einfach verschieben, anstatt eine Kopie zu erstellen.
#!/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/
Dies ist was ich als Befehl auf meinem System verwende ($HOME/bin/swapfiles
). Ich denke, es ist relativ unempfindlich gegen Schlechtigkeit.
#!/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"
Eine etwas gehärtete Version, die für Dateien und Verzeichnisse geeignet ist:
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
}
Dies funktioniert unter Linux. Nicht sicher über OS X.
Hardys Idee war gut genug für mich ... Ich habe also versucht, die folgenden beiden Dateien auszutauschen: "sendms.properties", "getsms.properties.swap" . Aber sobald ich diese Funktion als gleiches Argument bezeichnet habe, sendet "sms" .properties "dann wird diese Datei gelöscht. Um diese Art von FAIL zu vermeiden, habe ich ein paar Zeilen für mich hinzugefügt :-)
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
}
Nochmals vielen Dank Hardy ;-)
wenn Sie mv verwenden, bedeutet dies, dass Sie weniger Operationen ausführen müssen, keine endgültige Rm erforderlich ist. Außerdem ändert mv nur Verzeichniseinträge, sodass Sie keinen zusätzlichen Speicherplatz für die Kopie verwenden.
Temptationh ist dann die Implementierung einer Shell-Funktion swap () oder einer solchen Funktion. Wenn Sie extrem vorsichtig sind, überprüfen Sie die Fehlercodes. Könnte furchtbar zerstörerisch sein. Sie müssen auch nach bereits vorhandenen tmp-Dateien suchen.
Ein Problem hatte ich bei der Verwendung einer der hier bereitgestellten Lösungen: Ihre Dateinamen werden umgestellt.
Ich habe die Verwendung von basename
und dirname
eingebaut, um die Dateinamen intakt zu halten.
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
}
Ich habe das in bash und zsh getestet.
* Um zu klären, wie das besser ist:
Wenn Sie anfangen mit:
dir1/file2: this is file2
dir2/file1: this is file1
Die andere Lösungen würden am Ende mit:
dir1/file2: this is file1
dir2/file1: this is file2
Der Inhalt wird vertauscht, aber die Dateinamen sind geblieben. Meine Lösung macht es:
dir1/file1: this is file1
dir2/file2: this is file2
Die Namen von und werden vertauscht.
Hier ist ein swap
-Skript mit paranoider Fehlerüberprüfung, um den unwahrscheinlichen Fall eines Ausfalls zu vermeiden.
Skript:
#!/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
Sicher mv
statt cp
?
mv old tmp
mv curr old
mv tmp curr
Ich habe dies in einem Arbeitsskript, das ich geliefert habe. Es ist als Funktion geschrieben, aber Sie würden es aufrufen
d_swap lfile rfile
Das GNU mv hat die Option -b und die Option -T. Sie können Verzeichnisse mit dem Schalter -T Behandeln.
Die Anführungszeichen stehen für Dateinamen mit Leerzeichen.
Es ist ein wenig ausführlich, aber ich habe es oft mit Dateien und Verzeichnissen verwendet. Es kann Fälle geben, in denen Sie eine Datei mit dem Namen eines Verzeichnisses umbenennen möchten, dies wird jedoch von dieser Funktion nicht behandelt.
Dies ist nicht sehr effizient, wenn Sie nur die Dateien umbenennen möchten (sie dort belassen, wo sie sich befinden). Dies ist besser mit einer Shell-Variablen möglich.
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
}
Diese Funktion benennt Dateien um. Es verwendet einen temporären Namen (es setzt einen Punkt vor dem Namen), nur wenn sich die Dateien/Verzeichnisse im selben Verzeichnis befinden, was normalerweise der Fall ist.
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" )
}
Das ist viel schneller (es gibt kein Kopieren, nur Umbenennen). Es ist noch hässlicher. Und es wird alles umbenennen: Dateien, Verzeichnisse, Pipes, Geräte.