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

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

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

cp old tmp
cp curr old
cp tmp curr
rm tmp

Ответы [ 15 ]

2 голосов
/ 06 февраля 2013

Одна проблема, с которой я столкнулся при использовании любого из предложенных здесь решений: имена ваших файлов будут изменены.

Я включил использование basename и dirname, чтобы сохранить имена файлов без изменений *.

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
}

Я проверял это в bash и zsh.


* Итак, чтобы уточнить, как это лучше:

Если вы начинаете с:

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

другие решения будут заканчиваться на:

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

Содержимое поменяно местами, но имена файлов остались . Мое решение делает это:

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

Меняются имена и .

2 голосов
/ 12 июля 2009

Использование mv означает, что у вас меньше операций, нет необходимости в конечном rm, также mv изменяет только записи каталога, поэтому вы не используете дополнительное дисковое пространство для копии.

Затем Temptationh должен реализовать функцию swap () оболочки или что-то подобное. Если вы действительно очень осторожны, чтобы проверить коды ошибок. Может быть ужасно разрушительным. Также необходимо проверить наличие существующего файла tmp.

0 голосов
/ 28 июня 2014

У меня есть это в рабочем сценарии, который я доставил. Он написан как функция, но вы бы вызвали его

d_swap lfile rfile

У GNU mv есть ключ -b и -T. Вы можете иметь дело с каталогами, используя -T переключатель.

Кавычки предназначены для имен файлов с пробелами.

Это немного многословно, но я много раз использовал его с файлами и каталогами. Могут быть случаи, когда вы захотите переименовать файл с именем каталога, но эта функция не обрабатывается.

Это не очень эффективно, если все, что вы хотите сделать, это переименовать файлы (оставить их там, где они есть), что лучше сделать с помощью переменной оболочки.

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
}

Эта функция будет переименовывать файлы. Он использует временное имя (ставит точку «.» Перед именем) на тот случай, если файлы / каталоги находятся в одном каталоге, как это обычно бывает.

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

Это намного быстрее (нет копирования, просто переименование). Это еще страшнее. И он будет переименовывать что угодно: файлы, каталоги, каналы, устройства.

0 голосов
/ 12 июля 2009
mv old tmp
mv curr old
mv tmp curr
0 голосов
/ 12 июля 2009

Конечно mv вместо cp?

...