Bash

在這個 bash 腳本中如何處理標準輸入?

  • February 10, 2017

我有一個 bash 腳本(名為opsin),它只管理 Java 二進製文件的呼叫。所有參數都轉發${@:1}到 Java 二進製文件。

#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
java -jar $DIR/../bin-java/opsin/opsin.jar ${@:1}

這個二進製文件 ,opsin.jar也接受stdin,所以你可以做

echo "abcd" | java -jar opsin.jar

但是我可以對上面的 bash 腳本做同樣的事情:

echo "abcd" | opsin

是如何stdin傳遞給

java -jar $DIR/../bin-java/opsin/opsin.jar ${@:1}

在 bash 腳本中?

魔法!

特別是,外殼fork(2)本身;這會產生兩個(大部分)相同的 shell 程序副本;值得注意的是,子 shell 程序從父 shell 程序繼承了標準輸入的副本:

  *  The child inherits copies of the parent’s set of open file  descrip-
     tors.   Each  file  descriptor  in the child refers to the same open
     file description (see open(2)) as the corresponding file  descriptor
     in  the parent.  This means that the two descriptors share open file
     status flags, current file offset, and signal-driven I/O  attributes
     (see the description of F_SETOWN and F_SETSIG in fcntl(2)).

然後,子shell程序會呼叫exec(3)launch java,即子shell程序將自己替換java為。通過此呼叫java獲得從父級繼承的文件描述符的副本,並可以對傳遞給它的標準輸入進行操作。

(如果在文件描述符上設置了“close on exec”標誌,可能會出現複雜情況,但這不是標準輸入(如標準輸入)的預設設置。)

此外,如果父 shell 在執行時不需要停留在記憶體java中,程式碼可以寫成:

#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
exec java -jar $DIR/../bin-java/opsin/opsin.jar ${@:1}

這樣就java替換了父 shell 程序,而不是將 shell 程序不必要地留在記憶體中。

有關更多詳細資訊,Unix 環境中的高級程式 (APUE) 有一些章節介紹了所涉及的各種 fork、exec、dup、管道系統呼叫。

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