Bash read/write file descriptors -- seek to start of file Bash read/write file descriptors -- seek to start of file unix unix

Bash read/write file descriptors -- seek to start of file


I found a way to do it in bash, but it's relying on an obscure feature of exec < /dev/stdin which actually can rewind the file descriptor of stdin according to http://linux-ip.net/misc/madlug/shell-tips/tip-1.txt:

F=$(mktemp)exec 3<> "$F"rm -f "$F"echo "Hello world" >&3{ exec < /dev/stdin; cat; } <&3

The write descriptor isn't affected by that so you can still append output to descriptor 3 before the cat.

Sadly I only got this working under Linux not under MacOS (BSD), even with the newest bash version. So it doesn't seem very portable.


If you ever do happen to want to seek on bash file descriptors, you can use a subprocess, since it inherits the file descriptors of the parent process. Here is an example C program to do this.

seekfd.c

#define _FILE_OFFSET_BITS 64#include <string.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <unistd.h>int main(int argc, char* argv[]){    /* Arguments: fd [offset [whence]]     * where     * fd: file descriptor to seek     * offset: number of bytes from position specified in whence     * whence: one of     *  SEEK_SET (==0): from start of file     *  SEEK_CUR (==1): from current position     *  SEEK_END (==2): from end of file     */    int fd;    long long scan_offset = 0;    off_t offset = 0;    int whence = SEEK_SET;    int errsv; int rv;    if (argc == 1) {        fprintf(stderr, "usage: seekfd fd [offset [whence]]\n");        exit(1);    }    if (argc >= 2) {        if (sscanf(argv[1], "%d", &fd) == EOF) {            errsv = errno;            fprintf(stderr, "%s: %s\n", argv[0], strerror(errsv));            exit(1);        }    }    if (argc >= 3) {        rv = sscanf(argv[2], "%lld", &scan_offset);        if (rv == EOF) {            errsv = errno;            fprintf(stderr, "%s: %s\n", argv[0], strerror(errsv));            exit(1);        }        offset = (off_t) scan_offset;    }    if (argc >= 4) {        if (sscanf(argv[3], "%d", &whence) == EOF) {            errsv = errno;            fprintf(stderr, "%s: %s\n", argv[0], strerror(errsv));            exit(1);        }    }    if (lseek(fd, offset, whence) == (off_t) -1) {        errsv = errno;        fprintf(stderr, "%s: %s\n", argv[0], strerror(errsv));        exit(2);    }    return 0;}


No. bash does not have any concept of "seeking" with its redirection. It reads/writes (mostly) from beginning to end in one long stream.