web-dev-qa-db-fra.com

Le plus court moyen d'échanger deux fichiers en bash

Deux fichiers peuvent-ils être échangés en bash?

Ou, peuvent-ils être échangés d'une manière plus courte que celle-ci:

cp old tmp
cp curr old
cp tmp curr
rm tmp
51
flybywire

Ajoutez ceci à votre .bashrc:

function swap()         
{
    local TMPFILE=tmp.$$
    mv "$1" $TMPFILE
    mv "$2" "$1"
    mv $TMPFILE "$2"
}

Si vous voulez gérer un échec potentiel d'opérations mv intermédiaires, cochez La réponse de Can Bal .

Veuillez noter que ni ceci, ni aucune autre réponse ne fournit une solution atomic, car il est impossible de mettre en œuvre de tels systèmes à l'aide d'appels système Linux et/ou de systèmes de fichiers Linux courants. Pour le noyau Darwin, consultez exchangedata syscall.

43
Hardy
$ mv old tmp && mv curr old && mv tmp curr

est légèrement plus efficace!

Enveloppé dans une fonction Shell réutilisable:

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

souhaitez-vous réellement les échanger?

mv new old -b

tu auras:

old and old~

si vous voulez avoir

old and old.old

vous pouvez utiliser -S pour changer ~ en votre suffixe personnalisé

mv new old -b -S .old
ls
old old.old

en utilisant cette approche, vous pouvez réellement les échanger plus rapidement, en utilisant seulement 2 mv:

mv new old -b && mv old~ new
26
Łukasz Rysiak

En combinant les meilleures réponses, je mets ceci dans mon ~/.bashrc:

function swap()
{
  tmpfile=$(mktemp $(dirname "$1")/XXXXXX)
  mv "$1" "$tmpfile" && mv "$2" "$1" &&  mv "$tmpfile" "$2"
}
10
Leslie Viljoen

Vous pouvez simplement les déplacer, au lieu de faire une copie.

#!/bin/sh
# Created by Wojtek Jamrozy (www.wojtekrj.net)
mv $1 cop_$1
mv $2 $1
mv cop_$1 $2

www.wojtekrj.net/2008/08/bash-script-to-swap-contents-of-files/

6
Zyphrax

C’est ce que j’utilise comme commande sur mon système ($HOME/bin/swapfiles). Je pense que c'est relativement résistant au mal.

#!/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

Une version quelque peu durcie qui fonctionne à la fois pour les fichiers et les répertoires:

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
}

Cela fonctionne sous Linux. Pas sûr de OS X.

4
cayhorstmann

L'idée de Hardy était suffisante pour moi ... J'ai donc essayé d'échanger "sendms.properties", "sendms.properties.swap" ..__ avec mes deux fichiers suivants. .properties "puis ce fichier supprimé. En évitant ce genre d'échec, j'ai ajouté une ligne pour moi :-)

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
}

Merci encore Hardy ;-)

3
tsoomo

utiliser mv signifie que vous avez une opération de moins, que vous n'avez pas besoin de la dernière version, mais que mv ne fait que modifier les entrées du répertoire, vous n'utilisez donc pas d'espace disque supplémentaire pour la copie.

Temptationh consiste alors à implémenter une fonction shell swap () ou autre. Si vous faites extrêmement attention à vérifier les codes d'erreur. Pourrait être horriblement destructeur. Il faut également vérifier s'il existe un fichier tmp préexistant. 

2
djna

Un problème que j'ai rencontré lors de l’utilisation de l’une des solutions fournies ici: vos noms de fichiers seront modifiés.

J'ai incorporé l'utilisation de basename et dirname pour conserver les noms de fichiers intacts *.

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
}

J'ai testé cela en bash et zsh.


* Donc, pour clarifier en quoi c'est mieux:

Si vous commencez avec:

dir1/file2: this is file2
dir2/file1: this is file1

Les autres solutions finiraient avec:

dir1/file2: this is file1
dir2/file1: this is file2

Le contenu est échangé mais le nom du fichier est resté. Ma solution le rend:

dir1/file1: this is file1
dir2/file2: this is file2

Les contenus et sont échangés.

2
adam_0

Voici un script swap avec vérification d'erreur paranoïde pour éviter les cas improbables d'échec.

  • si l'une des opérations échoue, c'est signalé.
  • le chemin du premier argument est utilisé pour le chemin temporaire (pour éviter le déplacement entre les systèmes de fichiers) .
  • dans le cas improbable où le deuxième mouvement échoue, le premier est restauré.

Scénario:

#!/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

mv au lieu de cp?

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

J'ai ceci dans un script de travail que j'ai livré. C'est écrit comme une fonction, mais vous l'invoqueriez

d_swap lfile rfile

Le GNU mv a les commutateurs -b et -T. Vous pouvez utiliser des répertoires à l’aide du commutateur -T

Les citations sont pour les noms de fichiers avec des espaces.

C'est un peu bavard, mais je l'ai utilisé plusieurs fois avec des fichiers et des répertoires. Dans certains cas, vous voudrez peut-être renommer un fichier avec le nom d'un répertoire, mais cela n'est pas géré par cette fonction.

Ce n'est pas très efficace si tout ce que vous voulez faire est de renommer les fichiers (en les laissant où ils sont), c'est mieux avec une variable 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
}

Cette fonction va renommer les fichiers. Il utilise un nom temporaire (il place un point "." Devant le nom) au cas où les fichiers/répertoires se trouvent dans le même répertoire, ce qui est généralement le cas.

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" )
}

C'est beaucoup plus rapide (il n'y a pas de copie, il suffit de renommer). C'est encore plus laid. Et tout sera renommé: fichiers, répertoires, pipes, périphériques.

0
Bonaparte