Кратчайший способ поменять два файла в bash - PullRequest
54 голосов
/ 12 июля 2009

Можно ли заменить два файла в bash?

Или их можно поменять местами короче:

cp old tmp
cp curr old
cp tmp curr
rm tmp

Ответы [ 15 ]

71 голосов
/ 12 июля 2009
$ mv old tmp && mv curr old && mv tmp curr

немного эффективнее!

Завернут в многоразовую функцию оболочки:

function swap()         
{
    local TMPFILE=tmp.$$
    mv "$1" $TMPFILE && mv "$2" "$1" && mv $TMPFILE "$2"
}
43 голосов
/ 13 июля 2009

Добавьте это к вашему .bashrc:

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

Если вы хотите обработать потенциальный сбой промежуточных mv операций, отметьте Can Bal's answer .

Обратите внимание, что ни этот, ни другие ответы не дают решения atomic , поскольку такое невозможно реализовать с помощью системных вызовов Linux и / или популярных файловых систем Linux. Для ядра Дарвина проверьте exchangedata syscall.

31 голосов
/ 12 июля 2009
tmpfile=$(mktemp $(dirname "$file1")/XXXXXX)
mv "$file1" "$tmpfile"
mv "$file2" "$file1"
mv "$tmpfile" "$file2"
27 голосов
/ 06 апреля 2012

Вы действительно хотите поменять их местами? я думаю, стоит упомянуть, что вы можете автоматически создавать резервные копии перезаписанного файла с помощью mv:

mv new old -b

вы получите:

old and old~

если вы хотите иметь

old and old.old

вы можете использовать -S, чтобы изменить ~ на ваш собственный суффикс

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

используя этот подход, вы можете поменять их местами быстрее, используя только 2 mv:

mv new old -b && mv old~ new
11 голосов
/ 18 июня 2012

Объединяя лучшие ответы, я помещаю это в мой ~ / .bashrc:

function swap()
{
  tmpfile=$(mktemp $(dirname "$1")/XXXXXX)
  mv "$1" "$tmpfile" && mv "$2" "$1" &&  mv "$tmpfile" "$2"
}
6 голосов
/ 12 июля 2009

Вы можете просто переместить их, вместо того, чтобы сделать копию.

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

4 голосов
/ 10 марта 2015

Это то, что я использую в качестве команды в моей системе ($HOME/bin/swapfiles). Я думаю, что он относительно устойчив к злу.

#!/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"
4 голосов
/ 21 марта 2014

Несколько усиленная версия, которая работает как с файлами, так и с каталогами:

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
}

Это работает в Linux. Не уверен насчет OS X.

3 голосов
/ 11 декабря 2012

Идея Харди была достаточно хороша для меня. Итак, я попробовал следующие два файла, чтобы поменять местами «sendms.properties», «sendms.properties.swap». Но как только я вызвал эту функцию как тот же аргумент «sendms.properties», этот файл удалили. Избегая такого рода неудач, я добавил для меня строку: -)

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
}

Еще раз спасибо, Харди; -)

2 голосов
/ 11 июня 2017

Вот скрипт swap с параноидальной проверкой ошибок, чтобы избежать маловероятного случая сбоя.

  • если какая-либо из операций не удалась, сообщается.
  • путь первого аргумента используется для временного пути (чтобы избежать перемещения между файловыми системами) .
  • в маловероятном случае, если второй ход не удался, первый восстанавливается.

Сценарий:

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