it-swarm.com.de

Kürzeste Möglichkeit, zwei Dateien in Bash auszutauschen

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
51
flybywire

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.

43
Hardy
$ 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"
}
68
Can Bal
tmpfile=$(mktemp $(dirname "$file1")/XXXXXX)
mv "$file1" "$tmpfile"
mv "$file2" "$file1"
mv "$tmpfile" "$file2"
31
cube

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
26
Łukasz Rysiak

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"
}
10
Leslie Viljoen

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/

6
Zyphrax

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"
5
Richard

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.

4
cayhorstmann

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 ;-)

3
tsoomo

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. 

2
djna

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.

2
adam_0

Hier ist ein swap-Skript mit paranoider Fehlerüberprüfung, um den unwahrscheinlichen Fall eines Ausfalls zu vermeiden.

  • wenn eine der Operationen fehlschlägt, wird dies gemeldet.
  • der Pfad des ersten Arguments wird für den temporären Pfad verwendet (um ein Wechseln zwischen Dateisystemen zu vermeiden) .
  • in dem unwahrscheinlichen Fall, dass der zweite Zug fehlschlägt, wird der erste wiederhergestellt.

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
2
ideasman42

Sicher mv statt cp?

0
Alastair
mv old tmp
mv curr old
mv tmp curr
0
arturh

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.

0
Bonaparte