Bash에서 /dev/fd/X를 작성하는 이식 가능한 방법

Bash에서 /dev/fd/X를 작성하는 이식 가능한 방법

파일을 사용하기 전에 삭제하고 싶기 때문에 이 예에서는 paste시작하기 전에 col1, col2...col1000의 링크를 해제하고 싶습니다.

exec 3< col1 4< col2 ... 1002< col1000
rm col1 col2 ... col1000
paste /dev/fd/3 /dev/fd/4 ... /dev/fd/1002

이는 GNU/Linux+bash에서 잘 작동합니다. 그러나 /dev/fd/X다른 시스템으로 이식할 수는 없습니다.

내가 사용할 수 있는 bash명령 대체는 다음과 같습니다 .

exec 3< col1 4< col2 ... 1002< col1000
rm col1 col2 ... col1000
paste <(cat <&3) <(cat <&4) ... <(cat <&1002)

하지만 이렇게 하면 파일당 하나의 프로세스가 필요합니다.

모든 시스템에서 Bash와 작동하는 방식으로 위의 내용을 작성할 수 있습니까? 어쩌면 특별한 Bash 구문이 있을까요?

답변1

가장 간단한 이식 가능한 솔루션은 파일 설명자 번호를 인수로 사용하고 paste파일 설명자 리디렉션이 포함된 내장 함수를 사용하여 이를 반복하는 함수로 바꾸는 것입니다.read

paste()
{
    at_least_one_read_succeeded=true
    while $at_least_one_read_succeeded
    do
        at_least_one_read_succeeded=false
        first_fd=true
        for fd in "$@"
        do
            if ! $first_fd
            then
                printf '\t'
            fi
            if IFS= read -r line <&"$fd"
            then
                at_least_one_read_succeeded=true
            fi
            printf '%s' "$line"
            first_fd=false
        done
        printf '\n'
    done
}

가장 큰 단점은 쉘의 내장 기능이 별도의 시스템 호출을 read수행할 수밖에 없기 때문에 속도가 훨씬 느리다는 것입니다.read각 바이트마다. 마찬가지로 printf명령을 호출할 때마다 최소한 하나의 write시스템 호출을 수행해야 합니다(이론적으로 누군가는 최적화 컴파일러와 JIT VM이 수행하는 것과 동일한 분석을 사용하여 이 경우 I/O를 최적화할 수 있는 셸을 작성할 수 있습니다). , 그러나 현재 그러한 쉘은 존재하지 않습니다). 대부분의 경우 최신 하드웨어에서는 그 차이가 여전히 무시할 수 있지만 예제에 수천 개의 파일이 포함되어 있으므로 실제로 성능 저하가 나타날 수 있으며 이는 사용 사례에서 중요합니다.

물론, 시간과 노력을 존중하는 것 외에는 쉘에서 자체적으로 버퍼링된 I/O를 롤링하는 것을 막을 수 있는 방법이 없습니다. 예를 들어, dd bs=4096 count=1한 번에 4096바이트를 각 FD에 대한 별도의 변수로 읽은 다음 줄 바꿈이 부족할 때까지 해당 줄을 가져올 수 있습니다. 예 를 들어 , 라는 bash 배열을 만들고 buffers다음을 buffers[$fd]=$(dd bs=4096 count=1 <$&fd)사용하여 읽을 수 있습니다. ${buffers[$fd]%%'$\n'*}솔직히 말해서, 이것을 고려하고 있고 col이러한 파일을 디스크에 보관하지 않는 것이 매우 중요하다면 이러한 열 파일의 전체 내용을 변수로 읽는 것을 고려할 수도 있습니다 bash. 데이터 크기는 모르겠습니다. 하지만 시스템이 bash그 정도의 할당을 허용하고 bash자체적으로 처리한다면진짜이러한 파일이 디스크에 남아 있지 않도록 방지하는 것도 중요하지만 콘텐츠가 지정된 파일에 전혀 닿지 않도록 하는 것도 충분히 중요할 수 있습니다.


하지만 한 발 뒤로 물러서면 이 정도면 충분하지 않을까요?

paste col1 col2 ... col1000 &  # background `paste`
# optionally, put a tiny sleep here
rm col1 col2 ... col1000
wait  # wait for `paste` to finish

col*솔직하게 말해서 파일이 정리되지 않을 수 있는 시간이 항상 있기 때문입니다 ( rm코드 또는 이전에 실행 중이던 코드에 rm정전이 발생하면 어떻게 될까요 paste?). 창이 부팅되고 시스템 호출을 통해 모든 매개변수에 도달할 paste때 창이 <=1초 동안 지속된다면(최신 하드웨어에서는 1밀리초 미만이면 충분할 수 있음) 정말 더 나쁠까요 ?open


고려해야 할 또 다른 사항은 임시 파일 시스템을 사용하는 것입니다. 많은 운영 체제는 특정 경로에 메모리 내 파일 시스템을 제공합니다. 예를 들어, 거의 모든 Linux 배포판에는 일반적으로 각 사용자가 개인 디렉터리를 얻는 마운트 지점이 /run있습니다 . 전원이 꺼지거나 상자를 재부팅하거나 종료하면 그 안의 모든 항목이 저장되지 않습니다. 실행해야 하는 다른 시스템이 무엇인지는 모르겠지만 해당 시스템에 임시 메모리 파일 시스템이 있는지 또는 재부팅 시 OS 디렉터리에 의해 지워지는 것이 보장되는지 확인하는 것이 좋습니다.tmpfs/run/$(id -u)tmpfs

관련 정보