簡體   English   中英

如何在bash中管道終端和同時編程

[英]How do I pipe to terminal and to program at the same time in bash

所以我試圖制作一個腳本來自動化我的C程序的測試(進出),我試圖讓輸入留在屏幕上,所以我知道發生了什么。

到目前為止我只嘗試過管道:

foo < input.txt

cat input.txt | tee dev/tty |foo

這還沒有為我工作。

所以假設輸入文件看起來像:

123
321

理想情況下,IO看起來像:

Input: 123
Echo: 123
Input: 321
Echo: 321

但它變成了

123
321
Input: 
Echo: 123
Input: 
Echo: 321

我可以使用其他方法來測試我的C程序嗎? 我可以在哪里開球可以達到這樣的效果? 我是否可以編寫另一個可以實現類似功能的C程序?

tee的stdout(對foo標准輸入)和重復的寫入(對你的tty字符開發)不及時同步。 你的tty比foo更快地消耗輸入,並且libc的緩沖使它更糟糕。 如果您正在尋求交互式自動化,請查看expect計划。

怎么樣簡單

cat input.txt ; cat input.txt | foo ;

第一部分打印輸入,第二部分打印輸出。

您可以選擇將print語句放在代碼中,以便在每次迭代時在相關輸出之前打印正在處理的輸入的子部分。

當以下腳本檢測到它在標准輸入的read()系統調用中被阻塞時,會向程序輸入輸入,並在標准輸出上打印相同的文本。 結果,程序的輸出和標准輸入的內容被適當地交錯。

用法:

$ simulate_user_input program args ...

例:

$ cat > test_script <<'END'
#!/usr/bin/env bash
echo -n "First name: "
read -r first_name
echo -n "Second name: "
read -r second_name
echo "Hello $first_name $second_name"
END                                  

$ chmod +x test_script
$ ./simulate_user_input ./test_script <<< $'John\nSmith'
First name: John
Second name: Smith
Hello John Smith

simulate_user_input

#!/usr/bin/env bash

if [ $# -eq 0 ]
then
    cat<<END

Usage:

    $(basename "$0") command args ...

END
    exit 1
fi

#set -x
if [ "$1" == "-simulate" ]
then
    app_stdin="$2/app_stdin"
    user_stdin="$2/user_stdin"
    user_stdout="$2/user_stdout"
    exec > "$app_stdin" 3< "$user_stdin" 4> "$user_stdout"
    while read -r -n 6 -t 0.1 line
    do
        if [[ $line == 'read(0' ]]
        then
            read -u 3 -r line || { cat > /dev/null; exit 0; }
            echo "$line" >&4
            echo "$line"
        fi
    done
    exit 0
fi

cleanup()
{
    rm -rf "$tmpdir"
    if [ "$(jobs -r|wc -l)" -ne 0 ]
    then
        kill %1 %2
    fi
}

tmpdir="$(mktemp -d)"
trap "cleanup" EXIT
app_stdin="$tmpdir/app_stdin"
user_stdin="$tmpdir/user_stdin"
user_stdout="$tmpdir/user_stdout"
mkfifo "$app_stdin"
mkfifo "$user_stdin"
mkfifo "$user_stdout"

cat "$app_stdin"|strace -e read -o "|$0 -simulate '$tmpdir'" "$@" &
cat < "$user_stdout" &
cat > "$user_stdin"
wait

如果您的目標程序( foo )保證為每行輸入輸出一行,這是一個可以執行此操作的Python 2程序:

#!/usr/bin/env python
import sys, subprocess
sp = subprocess.Popen(sys.argv[1:], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
for input_line in sys.stdin:
    print('Input: ' + input_line.rstrip('\r\n'))
    sp.stdin.write(input_line)
    sp.stdin.flush()
    output_line = sp.stdout.readline()
    print('Output: ' + output_line.rstrip('\r\n'))

如果將其保存為tee.py ,則可以使用它進行測試

echo -e '123\n321' | tee.py cat -

對於通用的可重復測試,或

echo -e '123\n321' | tee.py foo

為您的具體例子。


PS:如果你想在Python 3中使用它,你必須改變兩行:

    sp.stdin.write(input_line.encode('utf-8'))

    output_line = sp.stdout.readline().decode('utf-8')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM