web-dev-qa-db-ja.com

stdinから変数に複数行の入力を読み込む方法と、Shell(sh、bash)で出力する方法

私がやりたいことは次のとおりです:

  1. stdinから変数Aに複数行の入力を読み込みます
  2. Aでさまざまな操作を行う
  3. パイプA区切り記号(\n\r\t、etc)別のコマンドへ

現在の問題は、readコマンドで読み込めないことです。改行で読み込めなくなるためです。

次のように、catでstdinを読み取ることができます。

my_var=`cat /dev/stdin`

、しかし、それを印刷する方法がわかりません。そのため、改行、タブ、およびその他の区切り文字はそのままです。

サンプルスクリプトは次のようになります。

#!/usr/local/bin/bash

A=`cat /dev/stdin`

if [ ${#A} -eq 0 ]; then
        exit 0
else
        cat ${A} | /usr/local/sbin/nextcommand
fi
55
kakas

これは私のために働いています:

myvar=`cat`

echo "$myvar"

$myvarを囲む引用符は重要です。

63
Tanktalus

Bashには、別の方法があります。 _man bash_言及:

コマンド置換$(cat file)は、同等の高速な$(< file)に置き換えることができます。

_$ myVar=$(</dev/stdin)
hello
this is test
$ echo "$myVar"
hello
this is test
_
24
Ingo Karkat

teeは仕事をする

#!/bin/bash
myVar=$(tee)
9

はい、それも私のために動作します。ありがとう。

myvar=`cat`

と同じです

myvar=`cat /dev/stdin`

はい、そうです。 bash manページから:

文字を二重引用符で囲むと、$、 `、\、および履歴展開が有効になっている場合は!を除き、引用符内のすべての文字のリテラル値が保持されます。文字$と `は、二重引用符で囲まれた特別な意味を保持します。

7
kakas

出力の最後で末尾の改行を保持することに関心がある場合は、これを使用します。

myVar=$(cat; echo x)
myVar=${myVar%x}
printf %s "$myVar"

これは here のトリックを使用します。

4
Ingo Karkat

[更新しました]

パイプに何もない場合、この割り当ては無期限にハングします...

_var="$(< /dev/stdin)"
_

ただし、最初の文字にタイムアウトreadを実行することでこれを防ぐことができます。タイムアウトになると、戻りコードは128を超え、STDINパイプ(別名_/dev/stdin_)が空であることがわかります。

それ以外の場合は、STDINの残りを取得します...

  • IFSコマンドに対してのみreadをNULLに設定
  • _-r_でエスケープをオフにする
  • _-d ''_を使用して読み取りの区切り文字を削除します。
  • そして最後に、最初に得たキャラクターにそれを追加します

したがって...

___=""
_stdin=""

read -N1 -t1 __  && {
  (( $? <= 128 ))  && {
    IFS= read -rd '' _stdin
    _stdin="$__$_stdin"
  }
}
_

この手法では、var="$(command ...)"コマンド置換の使用を回避します。これは、設計上、後続の改行を常に削除します。

コマンド置換が優先される場合、末尾の改行を保持するために、1つ以上の区切り文字を$()内の出力に追加し、それらを外部で取り除くことができます。

たとえば、最初のコマンドでは(note $(parens)、2番目では_${braces}_) ...

__stdin="$(awk '{print}; END {print "|||"}' /dev/stdin)"
_stdin="${_stdin%|||}"
_
3
DocSalvager