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
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.
$ 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"
}
tmpfile=$(mktemp $(dirname "$file1")/XXXXXX)
mv "$file1" "$tmpfile"
mv "$file2" "$file1"
mv "$tmpfile" "$file2"
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
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"
}
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/
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"
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.
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 ;-)
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.
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.
Voici un script swap
avec vérification d'erreur paranoïde pour éviter les cas improbables d'échec.
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
mv
au lieu de cp
?
mv old tmp
mv curr old
mv tmp curr
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.