如何在bash中切换文件输入和终端输入

时间:2016-08-05 00:49:27

标签: bash shell

我正在编写一个从文件中读取的bash脚本。从文件中读取后,我想提示用户输入,并从终端读取它。

这是我的代码的摘录:

while IFS=',' read -r a b c
do
    #a, b, c are read in from file
    data1=$a
    data2=$b
    data3=$c

    #later in the loop
    #answer should be read in from the terminal
    echo "Enter your answer to continue:"
    read answer

done

但是,目前我认为该脚本认为我试图从与answerab相同的输入文件中读取c。如何在文件和终端输入之间切换?

1 个答案:

答案 0 :(得分:4)

如果您的stdin已从文件重定向(即,您使用./yourscript <file调用),则使用/dev/tty从终端读取:

#!/bin/bash

exec 3</dev/tty || {
  echo "Unable to open TTY; this program needs to read from the user" >&2
  exit 1
}

while IFS= read -r line; do # iterate over lines from stdin
  if [[ $line = Q ]]; then
    echo "Getting input from the user to process $line" >&2
    read -r answer <&3 # read input from descriptor opened to /dev/tty earlier
  else
    echo "Processing $line internally"
  fi
done

如果您想跳过顶部的exec 3</dev/tty(在脚本开头只打开/dev/tty一次,允许稍后使用<&3从TTY读取) ,那么你可以写一下:

read -r answer </dev/tty

...每次要从终端执行读取时打开它。但是,您希望确保在循环中在这些情况下失败的情况下进行错误处理(例如,如果此代码是从cron作业运行的,则ssh调用作为参数传递的命令没有-t,或者 没有TTY的类似情况。)

或者,考虑在除stdin之外的描述符上打开文件 - 这里,我们使用文件描述符#3进行文件输入,并假设调用为./yourscript file(stdin指向终端):

#!/bin/bash
filename=$1

while IFS= read -r line <&3; do # reading file contents from FD 3
  if [[ $line = Q ]]; then
    echo "Getting input from the user to process $line" >&2
    read -r answer # reading user input by default from FD 0
  else
    echo "Processing $line internally" >&2
  fi
done 3<"$filename" # opening the file on FD 3