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




grep (10)

Ajoutez ceci à votre .bashrc:

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

Si vous voulez gérer les échecs potentiels d'opérations mv intermédiaires, cochez la réponse de Can Bal .

Veuillez noter que ni cela, ni aucune autre réponse ne fournissent une solution atomique , car il est impossible de les implémenter avec des appels système Linux et / ou des systèmes de fichiers Linux courants. Pour le noyau Darwin, vérifiez syscall exchangedata data.

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

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"

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

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 là 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.


L'idée de Hardy me suffisait. J'ai donc essayé d'échanger "sendms.properties", "sendms.properties.swap" dans les deux fichiers suivants. Mais une fois que j'ai appelé cette fonction avec le même argument "sendms.properties", ce fichier a été 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 ;-)


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 fichier 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 aboutiraient à:

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

Le contenu est échangé mais les noms de fichiers sont restés . Ma solution le rend:

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

Le contenu et les noms sont échangés.


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.



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.


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

mv old tmp
mv curr old
mv tmp curr






command-line