두 변수를 교환해야 하는 유명한 입문 프로그래밍 연습이 있습니다. 확실한 해결책은 세 번째 임시 변수를 사용하는 것입니다. 그러나 언어에 튜플과 같은 것이 있으면 인수를 역순으로 반환하는 매우 간단한 도우미 함수를 작성할 수 있습니다.
def swap(a: Int, b: Int): (Int, Int) = (b, a)
val (two, one) = swap(1, 2) // => (2, 1)
Linux에서의 파일 작업에서도 이것이 가능한지 궁금합니다. 예를 들어, 상황에 따라 바꾸고 싶은 구성이 있는 경우 두 개의 파일 이름을 가져와 해당 내용을 바꿀 수 있는 명령이 있습니까?
예를 들어, a.txt 파일의 내용이 "Hello"이고 b.txt의 내용이 "World"라고 가정합니다. 여기서 호출한 것을 호출한 후 swap
a.txt에 "World"를 포함하고 b.txt에 "Hello"를 포함하고 싶습니다.
이 문제는 스왑 파티션이 모든 검색 결과를 지배했기 때문에 처음 생각했던 것보다 조사하기가 더 어려웠습니다.
답변1
커널 수준에서 이 작업을 수행하는 Linux 관련 시스템 호출이 있습니다.
관련 시스템 호출은 다음과 같습니다.renameat2()
renameat()
이는 이 문제를 해결하기 위해 추가 특정 플래그와 함께 사용할 수 있는 Linux 특정 확장입니다 . Linux 3.15에 추가되었으며 glibc 지원은 glibc 2.28에 추가되었습니다.
원자 교환오래된 길그리고새로운 길. 두 경로 이름이 모두 존재해야 하지만 유형이 다를 수 있습니다. 예를 들어 하나는 비어 있지 않은 디렉토리이고 다른 하나는 기호 링크일 수 있습니다.
이 기능을 지원할 수 있는 파일 시스템에 대한 추가 제한이 있을 수 있습니다. 이것자식 검색2014년 이후 추가된 다양한 파일 시스템에 대한 지원 소개: ext4, 퓨즈, f2fs, shmem/tmpfs, xfs, gfs2, overlayfs, btrfs, ubifs, affs...
이 시스템 호출을 사용하기 위한 올바른 명령이 없는 경우 다음은 모든 기호가 "수동으로"(이 아키텍처 = 316 등) 원자적으로 해결되는 매우 아키텍처별(amd64/x86_64) Python의 예입니다. SYS_renameat2
C에서 시스템 호출이 수행하는 작업을 보여주는 및 이름의 스왑 파일:a
b
strace
$ echo Hello > a.txt; echo World > b.txt
$ cat a.txt
Hello
$ cat b.txt
World
$ strace -e trace=renameat2 python3 -c 'import ctypes; libc = ctypes.CDLL(None); libc.syscall(316, -100, b"a.txt", -100, b"b.txt", 2);'
renameat2(AT_FDCWD, "a.txt", AT_FDCWD, "b.txt", RENAME_EXCHANGE) = 0
+++ exited with 0 +++
$ cat a.txt
World
$ cat b.txt
Hello
답변2
그런 건 없는 것 같아요기준시스템 호출.그러나 Linux에는 하나가 있습니다.
전용 시스템 호출이 있든 없든 중요합니다. rename(a, tmp); rename(b, a); rename(tmp, b);
모든 시스템에서 이 작업을 수행할 수는 있지만 원자적이지는 않기 때문입니다. 동시에 실행 중인 다른 프로세스에서 a
이름을 바꾼 후 해당 프로세스를 열려고 하면 "파일을 찾을 수 없음" 오류가 나타날 수 있습니다. 먼저 교체하더라도 rename()
항상 존재 link()
하는지 확인하십시오 . 다른 프로세스에서 동일한 파일을 열고 가져올 수 a
있습니다 .a
b
다행스럽게도 두 개의 파일을 교환할 필요가 있는 경우는 많지 않습니다(또한 두 개의 변수를 교환하는 것이 일반적인 요구 사항인지 확실하지 않습니다). 대신, 리더가 부분적, 혼합 또는 손실된 데이터를 얻을 수 있는 지점을 남기지 않고 단일 파일 이름 뒤에 오는 내용을 바꾸는 것이 더 일반적입니다. 이 작업 rename()
은 link()
또는 을 통해 쉽게 수행할 수 있습니다 symlink()
.
한 구성 집합에서 다른 구성 집합으로 변경하는 예의 경우 활성 구성에 대한 기호 링크를 만든 다음 자동으로 링크를 바꿀 수 있습니다.
예를 들어 다음과 같은 경우
$ ls -l
total 8
-rw-r--r-- 1 ilkkachu ilkkachu 6 Oct 17 21:07 conf1
-rw-r--r-- 1 ilkkachu ilkkachu 13 Oct 17 21:07 conf2
lrwxrwxrwx 1 ilkkachu ilkkachu 5 Oct 17 21:07 current -> conf1
그러면 ln -sf conf2 current
자동으로 다음으로 변경됩니다.
$ ls -l
total 8
-rw-r--r-- 1 ilkkachu ilkkachu 6 Oct 17 21:07 conf1
-rw-r--r-- 1 ilkkachu ilkkachu 13 Oct 17 21:07 conf2
lrwxrwxrwx 1 ilkkachu ilkkachu 5 Oct 17 21:07 current -> conf2
conf1
마찬가지로 및를 동일한 파일에 대한 하드 링크로 사용 current
하고 링크를 로 바꿀 수 있습니다 ln -f conf2 current
.
답변3
피하고 싶은 것 같군요파일 내용 사본파일을 사용하여 이를 달성하는 두 가지 방법을 생각할 수 있습니다.
mv
내용을 복사하지 않고 임시 파일을 통해 파일 이름을 바꾸는 데 사용됩니다 .포인터와 유사한 심볼릭 링크를 사용하고 교체하는 대신 필요한 구성을 명시적으로 설정하십시오. 예를 들어
$ls a.txt b.txt Define_setcfg.bash $cata.txt 안녕하세요 $catb.txt 세계 $cat 정의_setcfg.bash 함수 setcfg() { echo Set 구성을 $1 # $1이 유효한 cfg 파일 이름으로 설정되었는지 확인해야 합니다. ln -sf $1actual.cfg # Actual.cfg라는 이름의 $1 심볼릭 링크를 생성합니다. } $ source ./define_setcfg.bash # 현재 bash에서 함수 정의 $ setcfg b.txt # setcfg 함수 사용 구성을 b.txt로 설정 $ ls -l # 지금 가지고 있는 것이 무엇인지 확인 총 12개 lrwxrwxrwx 1 사용자 이름 사용자 이름 5 10월 17일 18:33 Actual.cfg -> b.txt -rw-rw-r-- 1 사용자 이름 사용자 이름 6 10월 17일 18:08 a.txt -rw-rw-r-- 1 사용자 이름 사용자 이름 6 10월 17일 18:08 b.txt -rw-rw-r-- 1 사용자 이름 사용자 이름 161 10월 17일 18:25 Define_setcfg.bash $ setcfg a.txt # 매개변수 1로 a.txt를 제공하는 함수를 사용합니다. 구성을 a.txt로 설정 $ ls -l # 지금 가지고 있는 것이 무엇인지 확인 총 12개 lrwxrwxrwx 1 사용자 이름 사용자 이름 5 10월 17일 18:34 Actual.cfg -> a.txt -rw-rw-r-- 1 사용자 이름 사용자 이름 6 10월 17일 18:08 a.txt -rw-rw-r-- 1 사용자 이름 사용자 이름 6 10월 17일 18:08 b.txt -rw-rw-r-- 1 사용자 이름 사용자 이름 161 10월 17일 18:25 Define_setcfg.bash $
답변4
이러한 명령은 작성하기 쉬우므로 숫자가 존재하는지 의심됩니다. 그런데 왜?
당신이 정말로 해결해야 할 문제는 무엇인가? 대부분의 경우 더 좋은 방법이 있습니다.
특정 이름을 가진 파일을 읽는 프로그램이 있고 두 가지 버전이 필요한 경우 일반적으로 제가 하는 일은 파일 시스템에 가용성을 나타내는 이름이 있는 두 가지 버전을 두고 이름이 있는 기호 링크를 사용하여 그 중 하나를 가리키는 것입니다. 프로그램 이름입니다. 실제 사용. 그런 다음 (을 사용하여) 심볼릭 링크를 업데이트하여 ln -sf
둘 사이를 변경합니다.