Search code examples
linuxbashshellgrep

Why the file describer redirected changes after grep command?


$exec 3<input.txt
$sleep 60 >&3 &
[1] 32524
$ cd/proc/32534/fd 
$ ls -l
lrwx------. 1 zhangchen zhangchen 64 Sep 24 18:29 0 -> /dev/pts/0
lr-x------. 1 zhangchen zhangchen 64 Sep 24 18:29 1 -> /home/zhangchen/input.txt
lrwx------. 1 zhangchen zhangchen 64 Sep 24 18:29 2 -> /dev/pts/0
lr-x------. 1 zhangchen zhangchen 64 Sep 24 18:29 3 -> /home/zhangchen/input.txt

$grep test_word <&3
test_word
$grep test_word <&3
[nothing output] 

Isn't grep search the file using describer 1, why did grep change the file describer 3?


Solution

  • It's not changing which file is open on FD 3, or what the contents of that file are. What changes is where in the file you're at.

    You're opening input.txt once.

    Before you run grep, the file pointer is at the front of the file.

    After you run grep, the file pointer is at the end of the file.

    It still points to the same file, but you're not at the front of it anymore, so there's no content left to read if the program you're running doesn't use seek() to rewind to the front.


    You can rewind to the front, if you run a program that does so:

    # Define a "rewind" function that uses Python
    rewind() {
      python -c 'import os, sys; os.lseek(int(sys.argv[1]), 0, os.SEEK_SET)' "$@"
    }
    
    # Create our input file
    echo 'test_word' >input.txt
    
    # Redirect from the input file
    exec 3<input.txt
    
    # Read from the input file once
    grep test_word <&3
    
    # Rewind the input file back to the beginning
    rewind 3
    
    # _Now_ we can read from the input file a second time
    grep test_word <&3