3

多くの組み込みbashコマンドと同様に、引数と入力を処理できるbashスクリプトを作成したいと思います。たとえば、並べ替えのように、処理できます

sort -k 1 -r input.txt
sort input.txt -k 1 -r
cat input.txt | sort -k 1 -r
sort -k 1 -r < input.txt
sort -k 1 -r <(cat input.txt)

スクリプトで引数と入力を同様の方法で処理できるようにしたい

myscript.sh -i 3 -b 4 input.txt
myscript.sh input.txt -i 3 -b 4
cat input.txt | myscript.sh -i 3 -b 4
myscript.sh -i 3 -b 4 < input.txt
myscript.sh -i 3 -b 4 <(cat input.txt)

これまでのところ、「read」と「getopts」の一部の機能のみを使用しており、自分でそれを実行しようとするとバグが発生する可能性があると考えています。

私の質問をより明確に述べるために、input.textの内容を

aaa
bbb
ccc

引数iとbの値を使用して何かを実行したいのですが、この例ではそれを出力します。私が欲しいサンプル出力は

i : 3
b : 4
aaa
bbb
ccc

この出力を提供するために上記のサンプルコマンドを処理するコードを書くための最良の方法は何ですか?

以下は、これまでで最高の@chepnerのサンドイッチのアイデアから得られたコードです。

#!/bin/bash -l
die () {
    echo >&2 "[exception] $@"
    exit 1
}

#parse param
while getopts "i:b:" OPTION; do
  case "$OPTION" in
    i)
      i="$OPTARG"
      ;;
    b)
      b="$OPTARG"
      ;;
    *)
      die "unrecognized option"
      ;;
  esac
done

if [ -e tmpfile ] 
then 
    rm tmpfile 
fi

shift $(($OPTIND - 1))
echo "i : "$i
echo "b : "$b
cat $1 > tmpfile

if read -t 0; then
    cat >> tmpfile
fi

cat tmpfile
4

2 に答える 2

6

エグゼクティブサマリー:read -t 0標準入力で利用可能な入力があるかどうかをテストするために使用できます。ステータス0で終了し、データは標準入力ですぐに利用可能になり(パイプまたはリダイレクトされたファイルを介して)、そうでない場合は1になります(たとえば、キーボードに接続されたままです)。次に、標準入力から読み取る必要があるかどうかに基づいて、スクリプトを分岐できます。

if read -t 0; then
    # Do one thing
else
    # Do something else
fi

私にとってトリッキーな部分は、何もパイプしない場合に標準入力の読み取りをブロックしないようにスクリプトを作成することでした。

これはうまくいくようです。改善を歓迎します。まず、すべてを標準入力で消費します。次に、引数として指定されたファイルを処理します。

# The first call to read only succeeds when there is input
# available on standard input. It does not actually consume
# a line, though.
if read -t 0; then
    # Read standard input normally
    while read line; do
        echo $line
    done
fi

# I'll assume you populate an array called input files
# while processing your arguments
for file in "${inputfiles[@]"; do 
    cat $file
done

これが無意味なラッパーsortで、標準入力を他の入力ファイルと組み合わせる別の方法を示しています。

if read -t 0; then
    cat | sort fileA fileB
else
    sort fileA file B
fi

sandwichコマンドラインで指定された2つのファイル間で標準入力(存在する場合)を出力する、もう少し便利なコマンドがあります。

#!/bin/bash

cat "$1"    # Output the first file
read -t 0 && cat # Pass through the standard input, if there is any
cat "$2"    # Output the second file

# cat "$1" - "$2" is almost the same, but requires standard input.

へのいくつかの呼び出しsandwich

$ sandwich header.txt footer.txt
$ sandwich header.txt footer.txt < body.txt
$ cat chapter1.txt chapter2.txt | sandwich <(echo "My header") <(echo "My footer") 

これはうまく機能しないので、改善の余地があります...

$ cat - | sandwich header.txt footer.txt
于 2012-08-28T13:11:10.523 に答える
0
cat input.txt | command
command < input.txt
command <(cat input.txt)

これら3つはアプリケーションの観点からは同一であり、シェルがリダイレクトを行います。アプリケーションはstdinを読み取るだけで済みます。

command input.txt
cat input.txt | command

これらは、処理するファイルのみが異なります。最初のファイルはinput.txtstdinであり、使用できるstdinであり-、ほとんどのunixコマンドがそれをサポートしています。

# echo "X" | cat -
X

したがって、デフォルトを設定します。filename=-ファイル名オプションを読み取ると、この変数が上書きされます。

于 2012-08-28T13:03:26.237 に答える