Io-Redirection

通過 bash 輸入重定向為多個 read(stdin) 呼叫提供輸入

  • May 22, 2021

假設我們有以下程序,它呼叫read()了兩次:

#include <stdio.h>
#include <unistd.h>

#define SIZE 0x100

int main(void)
{
   char buffer1[SIZE];
   char buffer2[SIZE];

   printf("Enter first input: \n");
   fflush(stdout);
   read(STDIN_FILENO, buffer1, SIZE);

   printf("Enter second input: \n");
   fflush(stdout);
   read(STDIN_FILENO, buffer2, SIZE);

   printf("\nFirst input:\n%s", buffer1);
   printf("\nSecond input:\n%s", buffer2);

   return 0;
}

當我們直接呼叫它時,我們可以輸入1第一個輸入和2第二個輸入以便列印:

First input:
1

Second input:
2

使用輸入重定向時如何實現這一點?

以下方法不起作用,因為第一個read消耗兩個輸入:

管道重定向:

$ { echo "1"; echo "2"; } | ./main_read
Enter first input:
Enter second input:

First input:
1
2

Second input:

Heredoc重定向:

$ ./main_read << EOF
1
2
EOF
Enter first input:
Enter second input:

First input:
1
2

Second input:

假設原始碼不能更改,並且輸入有時必須短於SIZE.

有什麼方法可以指示第一個read()停止閱讀,以便第二個read()消耗其餘的輸入?

這可能無法為您提供可接受的解決方案,但考慮到:

  • >

原始碼不能更改

  • shell 不能更改正在執行的程序的打開文件描述符指向的位置,也不能使正在執行的程序停止從文件描述符中讀取

您剩下的一些替代方案(沒有利用競爭條件)是:

  • 嘗試確保您的程序始終SIZE一次輸入字節:
{
 echo foo | dd bs=256 conv=sync
 echo bar | dd bs=256 conv=sync
} 2>/dev/null | ./main_read

輸出:

Enter first input: 
Enter second input: 

First input:
foo

Second input:
bar

這至少假設它SIZE小於管道緩衝區的大小。

  • 將程序的呼叫包裝在expect(或等效的)腳本中:
expect <<'EOT'
spawn ./main_read
expect "Enter first input:"
send "foo\n"
expect "Enter second input:"
send "bar\n"
expect eof
EOT

或者,以允許您將其他命令的輸出通過管道傳輸到它的方式,單獨讀取(假設您的作業系統為程序提供/dev/fd/n文件描述符):

echo foo | {
 echo bar |
   expect 4<&0 <<'EOT'
   spawn ./main_read
   set chan [open "/dev/fd/3"]
   gets $chan line
   expect "Enter first input:"
   send "$line\r"
   close $chan
   set chan [open "/dev/fd/4"]
   gets $chan line
   expect "Enter second input:"
   send "$line\r"
   close $chan
   expect eof
EOT
} 3<&0

在這兩種情況下,輸出都是:

spawn ./main_read
Enter first input: 
foo
Enter second input: 
bar

First input:
foo

Second input:
bar
  • 在允許以非阻塞方式打開管道的系統(例如 Linux)上,您可以使用 FIFO 使 shell 讀取和寫入您的程序。例如:
makefifo fifo
{
 exec 3<>fifo
 ./main_read 0<&3
} |
sh -c '
 # read a line from the pipe
 # read from a file or a different pipe, write to fifo
 # repeat ...
 # echo the output from the pipe
' mysh

雖然,如果expect您可以使用,我認為沒有令人信服的理由更喜歡重新發明它。

但是請注意,正如其他人所指出的那樣,不能保證您的所有程序reads 實際上都會獲得SIZE字節。

引用自:https://unix.stackexchange.com/questions/650814