可以在bash中交换两个文件吗?
或者,他们可以用比这更短的方式进行交换:
cp old tmp
cp curr old
cp tmp curr
rm tmp
答案 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)
使用此处提供的任何解决方案时遇到的一个问题是:您的文件名将被切换。
我使用了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
交换内容和名称。
答案 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" )
}
速度要快得多(没有复制,只是重命名)。这甚至更加丑陋。它将重命名任何内容:文件,目录,管道,设备。