Frage

Ich habe versucht, die Lese / Schreib-Dateideskriptor in bash zu verwenden, so dass ich die Datei löschen konnte, dass der Dateideskriptor später bezeichnet, als solche:

F=$(mktemp)
exec 3<> "$F"
rm -f "$F"

echo "Hello world" >&3
cat <&3

aber der cat Befehl gibt keine Ausgabe. Ich kann erreichen, was ich will, wenn ich separate Datei-Deskriptoren für das Lesen und Schreiben verwenden:

F=$(mktemp)
exec 3> "$F"
exec 4< "$F"
rm -f "$F"

echo "Hello world" >&3
cat <&4

, die Hello world druckt.

Ich vermutete, dass bash sucht nicht automatisch zu Beginn des Dateideskriptor, wenn Sie vom Schreiben schalten Sie es zu lesen, und die folgende Kombination von Bash und Python-Code bestätigt dies:

fdrw.sh

exec 3<> tmp
rm tmp

echo "Hello world" >&3
exec python fdrw.py

fdrw.py

import os  

f = os.fdopen(3)
print f.tell()
print f.read()

das gibt:

$ bash fdrw.sh
12

$ # This is the prompt reappearing

Gibt es eine Möglichkeit zu erreichen, was ich will bash nur mit?

War es hilfreich?

Lösung

Nein. bash hat kein Konzept der „Suche nach“ mit seiner Umleitung. Es liest / schreibt (meistens) aus in einem langen Strom Anfang bis Ende.

Andere Tipps

Wenn Sie jemals auf bash Filedeskriptoren suchen passieren zu wollen, können Sie einen Subprozess verwenden, da es die Datei-Deskriptoren des Elternprozesses erbt. Hier ist ein Beispiel C-Programm, dies zu tun.

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;
}

Ich fand einen Weg, um es in bash zu tun, aber es ist auf ein obskures Merkmale exec < /dev/stdin verlassen, die den Dateideskriptor tatsächlich zurückspulen stdin nach 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

Der Schreib Descriptor ist davon nicht betroffen, so dass Sie immer noch Ausgang Descriptor anhängen 3 vor der Katze.

Leider habe ich nur diese Arbeit unter Linux nicht unter MacOS (BSD), auch mit der neuesten Version bash. So ist es nicht sehr tragbar scheint.

Versuchen Sie, die Befehlsfolge zu ändern:

F=$(mktemp tmp.XXXXXX)
exec 3<> "$F"
echo "Hello world" > "$F"
rm -f "$F"

#echo "Hello world" >&3
cat <&3

Wenn Sie ein Datei-Descriptor in bash so zu öffnen, wird es zugänglich als Datei in /dev/fd/. Auf dass Sie cat tun können, und es wird von Anfang an, oder append (echo "something" >> /dev/fd/3) gelesen, und es wird es bis zum Ende hinzuzufügen. Zumindest auf meinem System verhält es sich auf diese Weise. (Auf der anderen Seite kann ich nicht in der Lage sein scheinen „cat <& 3“ zur Arbeit zu kommen, auch wenn ich auf den Deskriptor jede Schreiben nicht tun).

#!/bin/bash
F=$(mktemp tmp.XXXXXX)
exec 3<> $F
rm $F

echo "Hello world" >&3
cat /dev/fd/3

Wie vorgeschlagen in anderer Antwort , cat wird die Dateibeschreibung für Sie zurückspulen vor dem Lesen, da sie es denkt, dass nur eine reguläre Datei.

Um 'rewind' der Dateideskriptor, können Sie einfach /proc/self/fd/3

Test-Skript:

#!/bin/bash

# Fill data
FILE=test
date +%FT%T >$FILE

# Open the file descriptor and delete the file
exec 5<>$FILE
rm -rf $FILE

# Check state of the file
# should return an error as the file has been deleted
file $FILE

# Check that you still can do multiple reads or additions
for i in {0..5}; do
    echo ----- $i -----

    echo . >>/proc/self/fd/5
    cat /proc/self/fd/5

    echo
    sleep 1
done

Versuchen Sie kill -9 das Skript während er ausgeführt wird, werden Sie, dass im Gegensatz zu sehen, was mit dem Trap-Verfahren geschieht, wird die Datei tatsächlich gelöscht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top