file
두 파일( 및 ) file_1
의 파일 이름을 바꿔야 합니다 . 다음 코드를 사용하고 있습니다.
mv file .phfile
mv file_1 file
mv .phfile file
이 방법은 작동하지만 버그가 많고 때로는 데이터 손실이 발생할 수도 있습니다. 더 좋은 방법이 있나요?
답변1
답변2
기존 Unix 시스템에서는 파일을 교환하는 저수준 방법이 없으므로 중간 임시 이름을 사용해야 합니다. 견고성을 위해 임시 이름이 다른 프로그램에서 사용되지 않고(따라서 에서도 사용됨 mktemp
) 파일 중 하나와 동일한 파일 시스템에 있는지 확인하십시오. 그렇지 않으면 파일 이름이 바뀌는 대신 불필요하게 복사됩니다. .
swap_files () {
tmp_name=$(TMPDIR=$(dirname -- "$1") mktemp) &&
mv -f -- "$1" "$tmp_name" &&
mv -f -- "$2" "$1" &&
mv -f -- "$tmp_name" "$2"
}
swap_files file file_1
오류가 발생하면 첫 번째 파일은 여전히 임시 이름을 가질 수 있지만 두 번째 파일은 이동되었거나 이동되지 않았을 수 있습니다. 가동 중단 및 충돌 발생 시 견고해야 하는 경우 임시 이름이 두 개인 변형이 복구하기 더 쉬울 수 있습니다.
swap_files2 () {
tmp_dir1=$(TMPDIR=$(dirname -- "$1") mktemp -d .swap_files.XXXXXXXXXXXX) &&
tmp_dir2=$(TMPDIR=$(dirname -- "$2") mktemp -d .swap_files.XXXXXXXXXXXX) &&
mv -f -- "$1" "$tmp_dir1/" &&
mv -f -- "$2" "$tmp_dir2/" &&
mv -f -- "$tmp_dir1/"* "$1" &&
mv -f -- "$tmp_dir2/"* "$2" &&
rmdir -- "$tmp_dir1" "$tmp_dir2"
}
재부팅 후에도 임시 디렉터리가 .swap_files.????????????
지속 되면 정전으로 인해 파일 교환이 중단되었음을 의미합니다. 파일 중 하나는 제자리로 이동했지만 다른 하나는 이동하지 않았을 수 있으므로 여기의 코드는 원하는 복구 종류에 따라 모든 경우를 처리하지는 않습니다.
최신 Linux 커널(2014년 6월 출시된 3.15 기준) 파일 교환을 위한 시스템 호출이 있습니다. renameat2(…, RENAME_EXCHANGE)
그러나 범용 명령줄 유틸리티는 없는 것 같습니다. glibc 지원도 최근에야 추가되었습니다(2.28, 2018년 8월 출시).
답변3
파티에 조금 늦었지만최신 버전과 이전 버전의 Linux에서 스왑 파일의 이름을 자동으로 지정할 수 있습니다.tcc
또는 사용 gcc
(모든 주요 Linux 배포판에서 사용 가능)적시 생산여러분 자신은 올바른 커널 시스템 호출을 가져와 사용하는 저수준 도구입니다. 타사 도구가 필요하지 않습니다.
swapname() {
tcc -run - "$@" <<"CODE"
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/syscall.h>
// Ubuntu 18.04 does not define RENAME_EXCHANGE
// Value obtained manually from '/usr/include/linux/fs.h'
// You should switch to RENAME_EXCHANGE on modern systems
// Just remove the following line, then remove the `local_`
// prefix where it appears later in this function.
int local_RENAME_EXCHANGE = (1 << 1);
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "Error: Could not swap names. Usage: %s PATH1 PATH2\n", argv[0]);
return 2;
}
int r = syscall(
SYS_renameat2,
AT_FDCWD, argv[1],
AT_FDCWD, argv[2],
local_RENAME_EXCHANGE
);
if (r < 0) {
perror("Error: Could not swap names");
return 1;
}
else return 0;
}
CODE
}
다음과 같이 이 bash 기능을 실행하면 파일 이름이 깨끗하고 원자적으로 교체됩니다.
swapname "/path/to/file-1" "/path/to/file-2"
두 파일이 모두 동일한 파일 시스템 마운트 지점에 있어야 할 수도 renameat2
있습니다 . RENAME_EXCHANGE
매뉴얼 페이지의 오류 섹션을 참조하십시오 renameat2
(예:rename(2)
) 자세한 내용을 알아보세요.
TCC 대신 GCC를 사용하세요
gcc
대신 사용하려면 tcc
으로 시작하는 줄을 제거 tcc -run ...
하고 그 자리에 다음 줄을 추가하세요.
( EXEC="$(mktemp)" && gcc -x c - -o "$EXEC" && "$EXEC" "$@"; rm "$EXEC" ) <<"CODE"
답변4
이것이 내가 사용한 것입니다.
file1=1stfile
file2=2ndfile
tempdir="$(mktemp -d)"
mv "$file1" "$tempdir/tmpfile" &&
mv "$file2" "$file1" &&
mv "$tempdir/tmpfile" "$file2" &&
rm -rf "$tempdir"