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

时间:2009-07-12 12:01:35

标签: linux bash command-line

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

或者,他们可以用比这更短的方式进行交换:

cp old tmp
cp curr old
cp tmp curr
rm tmp

15 个答案:

答案 0 :(得分:70)

$ mv old tmp && mv curr old && mv tmp curr

效率稍高!

包装成可重复使用的shell函数:

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

答案 1 :(得分:43)

将此添加到.bashrc:

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

如果您想处理中间mv操作的潜在失败,请检查Can Bal's answer

请注意,这个或其他答案都没有提供 atomic 解决方案,因为使用Linux系统调用和/或流行的Linux文件系统无法实现。对于Darwin内核,请检查exchangedata系统调用。

答案 2 :(得分:31)

tmpfile=$(mktemp $(dirname "$file1")/XXXXXX)
mv "$file1" "$tmpfile"
mv "$file2" "$file1"
mv "$tmpfile" "$file2"

答案 3 :(得分:27)

你真的想交换它们吗? 我认为值得一提的是你可以使用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

答案 4 :(得分:10)

结合最佳答案,我把它放在我的〜/ .bashrc中:

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

答案 5 :(得分: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 :(得分: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不确定。

答案 7 :(得分:4)

这是我在系统上使用的命令($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"

答案 8 :(得分:3)

哈代的想法对我来说已经足够了。 所以我尝试了以下两个文件来交换“sendsms.properties”,“sendsms.properties.swap”。 但是,一旦我将此函数称为相同参数“sendsms.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
}

再次感谢哈代; - )

答案 9 :(得分:2)

使用mv意味着您只需少一个操作,不需要最终的rm,mv只是更改目录条目,因此您不会为副本使用额外的磁盘空间。

Temptationh然后是实现shell函数swap()或其他一些。如果您非常小心,请检查错误代码。可能是非常具有破坏性的。还需要检查预先存在的tmp文件。

答案 10 :(得分:2)

使用此处提供的任何解决方案时遇到的一个问题是:您的文件名将被切换。

我使用了basenamedirname来保持文件名完整*。

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

交换内容名称。

答案 11 :(得分: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

答案 12 :(得分:0)

肯定mv代替cp

答案 13 :(得分:0)

mv old tmp
mv curr old
mv tmp curr

答案 14 :(得分: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
}

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

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

速度要快得多(没有复制,只是重命名)。这甚至更加丑陋。它将重命名任何内容:文件,目录,管道,设备。