web-dev-qa-db-ja.com

bash:ファイルの読み取り中にユーザー入力を要求する

タブ区切りファイルを解析するbashスクリプトに取り組んでいます。ファイルに「プロンプト」という単語が含まれている場合、スクリプトはユーザーに値の入力を求める必要があります。

ファイルの読み取り中、「読み取り」コマンドは単純にスキップされるため、「読み取り」コマンドは標準入力から読み取ることができないようです。

ファイルからの読み取りと標準入力からの読み取りの両方を行うための回避策はありますか?

注:スクリプトはGit BashとMacOSの両方で実行する必要があります。

以下は、失敗する小さなコード例です。

#!/bin/bash

#for debugging
set "-x"


while IFS=$'\r' read -r line || [[ -n "$line" ]]; do
  [[ -z $line ]] && continue

  IFS=$'\t' read -a fields <<<"$line"

  command=${fields[0]}

  echo "PROCESSING "$command
  if [[ "Prompt" = $command ]]; then
    read -p 'Please enter a value: ' aValue
    echo
  else 
    echo "Doing something else for "$command
  fi
done < "$1"

出力:

$ ./promptTest.sh promptTest.tsv
+ IFS=$'\r'
+ read -r line
+ [[ -z something       else ]]
+ IFS=' '
+ read -a fields
+ command=something
+ echo 'PROCESSING something'
PROCESSING something
+ [[ Prompt = something ]]
+ echo 'Doing something else for something'
Doing something else for something
+ IFS=$'\r'
+ read -r line
+ [[ -z Prompt ]]
+ IFS=' '
+ read -a fields
+ command=Prompt
+ echo 'PROCESSING Prompt'
PROCESSING Prompt
+ [[ Prompt = Prompt ]]
+ read -p 'Please enter a value: ' aValue
+ echo

+ IFS=$'\r'
+ read -r line
+ [[ -n '' ]]

Tsvファイルの例:

$ cat promptTest.tsv
something       else
Prompt
otherthing       nelse
4
Bernie Lenz

最も簡単な方法は、/dev/ttyは、キーボード入力の読み取りとして。

例えば:

#!/bin/bash

echo hello | while read line
do
  echo We read the line: $line
  echo is this correct?
  read answer < /dev/tty
  echo You responded $answer
done

これをターミナルで実行しないと壊れてしまい、プログラムに入力をリダイレクトすることはできませんが、それ以外はかなりうまくいきます。

より一般的には、元の標準入力に基づいて新しいファイルハンドルを取得し、そこから読み取ることができます。 exec行とreadに注意してください

#!/bin/bash

exec 3<&0

echo hello | while read line
do
  echo We read the line: $line
  echo is this correct?
  read answer <&3
  echo You responded $answer
done

どちらの場合も、プログラムは次のようになります。

% ./y
We read the line: hello
is this correct?
yes
You responded yes

2番目のバリエーションでは、入力をリダイレクトすることもできます

% echo yes | ./y
We read the line: hello
is this correct?
You responded yes
3
Stephen Harris

これは、SO Q&Aタイトル: Bashでファイルまたはstdinから読み取る方法? は、探しているように聞こえる方法を強調するこのメソッドを示しています。

while read line
do
  echo "$line"
done < "${1:-/dev/stdin}"
1
slm

リダイレクトを行う前に、標準入力を複製できます。

#!/bin/bash
# Assuming here fd 4 is unused.  Dup file descriptor 0 (stdin) to
# file descriptor 4
exec 4<&0 

while read x; do # Read from stdin (the file b/c of redirect below)
    echo "From $1: $x"
    read y <&4 # Read from file descriptor 4 (the original stdin)
    echo "From keyboard: $y"
done < "$1"
1
Andy Dalton