在 bash 中交换两个文件的最短方法

问题描述 投票:0回答:16

bash 中可以交换两个文件吗?

或者,可以用比这更短的方式交换它们吗:

cp old tmp
cp curr old
cp tmp curr
rm tmp
linux bash command-line
16个回答
92
投票
$ mv old tmp && mv curr old && mv tmp curr

效率稍微高一点!

包装成可重用的shell函数:

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

52
投票

将其添加到您的 .bashrc 中:

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

如果您想处理中间

mv
操作的潜在失败,请检查 Can Bal 的答案

请注意,这个答案和其他答案都没有提供“原子”解决方案,因为不可能使用 Linux 系统调用和/或流行的 Linux 文件系统来实现这种解决方案。对于 Darwin 内核,请检查 exchangedata 系统调用。

    


36
投票


35
投票

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



16
投票

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



6
投票

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


6
投票
$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
投票

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
投票

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
投票

接下来的诱惑是实现 shell 函数 swap() 或类似的函数。如果您确实要格外小心地检查错误代码。可能具有可怕的破坏性。还需要检查预先存在的 tmp 文件。


2
投票

我合并使用

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
投票
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



0
投票
mv

而不是

cp
    


0
投票


0
投票

d_swap lfile rfile

GNU mv 有 -b 和 -T 开关。您可以使用 -T 处理目录
开关。

引号用于带空格的文件名。

这有点冗长,但我已经在文件和目录中多次使用过它。在某些情况下,您可能希望使用目录所具有的名称重命名文件,但这不是由此函数处理的。

如果您只想重命名文件(将它们保留在原来的位置),这不是很有效,最好使用 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 }

此功能将重命名文件。它使用临时名称(在名称前面放置一个点“.”),以防文件/目录位于同一目录中(通常是这种情况)。

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
投票

qmv(来自 Debian 中的

rename_utils
包)
。它的功能更强大,因为它允许您使用文本编辑器批量重命名批量文件,但具体而言,它可以检测并处理循环重命名。
示例:

当然它太强大了,这就是我来这里的原因,但由于之前没有人提到过这一点,我想我应该补充一下。

© www.soinside.com 2019 - 2024. All rights reserved.