development

Bash에서 두 파일을 교환하는 가장 짧은 방법

big-blog 2020. 12. 31. 23:23
반응형

Bash에서 두 파일을 교환하는 가장 짧은 방법


bash에서 두 개의 파일을 바꿀 수 있습니까?

또는 다음보다 짧은 방법으로 교체 할 수 있습니다.

cp old tmp
cp curr old
cp tmp curr
rm tmp

.bashrc에 다음을 추가하십시오.

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

중간 mv작업 의 잠재적 인 실패를 처리 하려면 Can Bal의 답변을 확인하십시오 .

Linux 시스템 호출 및 / 또는 널리 사용되는 Linux 파일 시스템을 사용하여 구현하는 것이 불가능하기 때문에 이것도 다른 답변도 원자 솔루션을 제공하지 않습니다 . Darwin 커널의 경우 exchangedatasyscall을 확인하십시오 .


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

약간 더 효율적입니다!

재사용 가능한 쉘 기능에 래핑 :

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

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

실제로 교환 하시겠습니까? mv로 덮어 쓴 파일을 자동으로 백업 할 수 있다는 점을 언급 할 가치가 있다고 생각합니다.

mv new old -b

당신은 얻을 것이다:

old and old~

당신이 갖고 싶다면

old and old.old

-S를 사용하여 ~를 사용자 지정 접미사로 변경할 수 있습니다.

mv new old -b -S .old
ls
old old.old

이 방법을 사용하면 실제로 2mv 만 사용하여 더 빠르게 교체 할 수 있습니다.

mv new old -b && mv old~ new

최고의 답변을 결합하여 ~ / .bashrc에 넣습니다.

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

복사본을 만드는 대신 간단히 이동할 수 있습니다.

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


파일과 디렉토리 모두에서 작동하는 다소 강화 된 버전 :

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에 대해 잘 모르겠습니다.


이것은 내 시스템에서 명령으로 사용하는 것입니다 ( $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"

Hardy의 아이디어는 나에게 충분했습니다. 그래서 "sendsms.properties", "sendsms.properties.swap"을 교체하기 위해 다음 두 파일을 시도했습니다. 그러나이 함수를 동일한 인수 "sendsms.properties"로 호출하면이 파일이 삭제되었습니다. 이런 종류의 FAIL 피하기 나는 나를 위해 몇 줄을 추가했습니다 :-)

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
}

다시 한 번 감사합니다 Hardy ;-)


mv를 사용하면 작업이 하나 더 적고 최종 rm이 필요하지 않으며 mv는 디렉토리 항목 만 변경하므로 복사본에 추가 디스크 공간을 사용하지 않습니다.

유혹은 쉘 함수 swap () 등을 구현하는 것입니다. 오류 코드를 확인하는 데 매우주의해야합니다. 끔찍하게 파괴적 일 수 있습니다. 또한 기존 tmp 파일을 확인해야합니다.


여기에 제공된 솔루션을 사용할 때 내가 가진 한 가지 문제는 파일 이름이 변경된다는 것입니다.

파일 이름을 그대로 유지하기 위해 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

내용 이름이 바뀝니다.


다음은 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

확실히 mv대신 cp?


mv old tmp
mv curr old
mv tmp curr

내가 전달한 작업 스크립트에 이것을 가지고 있습니다. 함수로 작성되었지만 호출 할 수 있습니다.

d_swap lfile rfile

GNU mv에는 -b 및 -T 스위치가 있습니다. -T 스위치를 사용하여 디렉토리를 처리 할 수 ​​있습니다.

따옴표는 공백이있는 파일 이름입니다.

It's a bit verbose, but I've used it many times with both files and directories. There might be cases where you would want to rename a file with the name a directory had, but that isn't handled by this function.

This isn't very efficient if all you want to do is rename the files (leaving them where they are), that is better done with a shell variable.

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
}

This function will rename files. It uses a temp name (it puts a dot '.' in front of the name) just in case the files/directories are in the same directory, which is usually the case.

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

That is a lot faster (there's no copying, just renaming). It is even uglier. And it will rename anything: files, directories, pipes, devices.

ReferenceURL : https://stackoverflow.com/questions/1115904/shortest-way-to-swap-two-files-in-bash

반응형