linux - tutorial - 在bash中交換兩個文件的最短方法




the linux command line中文 (10)

可以用bash交換兩個文件嗎?

或者,它們可以以比這更短的方式交換:

cp old tmp
cp curr old
cp tmp curr
rm tmp

一個有點硬化的版本,適用於文件和目錄:

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不確定。



使用mv意味著你只需要少一個操作,不需要最終的rm,mv只是更改目錄條目,因此你不會為副本使用額外的磁盤空間。

Temptationh然後是實現shell函數swap()或其他一些。 如果您非常小心,請檢查錯誤代碼。 可能是非常具有破壞性的。 還需要檢查預先存在的tmp文件。


使用此處提供的任何解決方案時遇到的一個問題是:您的文件名將被切換。

我結合使用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

交換內容名稱。


將其添加到.bashrc:

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

如果您想處理中間mv操作的潛在故障,請檢查Can Bal的答案 。

請注意,這個或其他答案都沒有提供原子解決方案,因為使用Linux系統調用和/或流行的Linux文件系統是不可能實現的。 對於Darwin內核,請檢查encryptedata系統調用。


我在我發布的工作腳本中有這個。 它是作為一個函數編寫的,但你會調用它

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

這要快得多(沒有復制,只是重命名)。 這甚至更加醜陋。 它將重命名任何東西:文件,目錄,管道,設備。


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

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

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

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

效率稍高!

包裝成可重複使用的shell功能:

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

mv old tmp
mv curr old
mv tmp curr




command-line