web-dev-qa-db-ja.com

ファイルまたは標準入力からの入力を受け付けるスクリプトの書き方

ファイル名引数または標準入力からの入力を受け付けるスクリプトを書くにはどうすればよいでしょうか。

たとえば、lessをこのように使うことができます。 less filenameと同等にcat filename | lessを実行できます。

そうするための「箱から出して」簡単な方法はありますか?それともホイールを作り直して、スクリプトに少しロジックを書く必要がありますか?

55
gilad hoch

ファイル引数がスクリプトの最初の引数である場合は、引数($1)があり、それがファイルであることをテストします。そうでなければstdinからの入力を読みます -

だからあなたのスクリプトはこのようなものを含むことができます:

#!/bin/bash
[ $# -ge 1 -a -f "$1" ] && input="$1" || input="-"
cat $input

例えばそれならあなたは次のようにスクリプトを呼び出すことができます

./myscript.sh filename

または

who | ./myscript.sh

編集スクリプトの説明:

[ $# -ge 1 -a -f "$1" ] - 少なくとも1つのコマンドライン引数($# -ge 1)AND(-a operator)が最初の引数がファイルの場合(-f "$ 1"がファイルの場合はテスト)、テスト結果は真になります。

&&はシェルの論理AND演算子です。 testが真ならば、input="$1"を割り当て、cat $inputはファイルを出力します。

||はシェルの論理OR演算子です。テストが偽の場合、||に続くコマンドが解析されます。入力は「 - 」に割り当てられます。 cat -はキーボードから読み込みます。

要約すると、スクリプトの引数が指定され、それがファイルの場合、変数の入力がファイル名に割り当てられます。有効な引数がない場合、catはキーボードから読み取ります。

57
suspectus

readは標準入力から読み込みます。ファイル(./script <someinput)またはパイプ(dosomething | ./script)を介してリダイレクトしても、動作が異なります。

あなたがしなければならないのはinputのすべての行をループすることです(そしてそれはfileの中の行を繰り返し処理するのと変わりません)。

(サンプルコード、1行のみ処理)

#!/bin/bash

read var
echo $var

標準入力の最初の行をエコーし​​ます(<または|を介して)。

12
Lukasz Daniluk

最も簡単な方法はstdinを自分自身にリダイレクトすることです。

if [ "$1" ] ; then exec < "$1" ; fi

あるいはもっと簡潔な形式を好むなら:

test "$1" && exec < "$1"

今すぐあなたのスクリプトの残りの部分は標準入力から読み取ることができます。もちろん、ファイル名の位置を"$1"としてハードコーディングするのではなく、より高度なオプション解析でも同様に実行できます。

4
R..

どのシェルを使用するつもりなのか言及していないので、bashを想定します。ただし、これらはシェル全体で非常に標準的なものです。

ファイル引数

引数は変数$1-$nを介してアクセスできます($0はプログラムの実行に使用されたコマンドを返します)。たとえば、n個のファイルを区切り文字でcatsするスクリプトがあるとします。

#!/usr/bin/env bash
#
# Parameters:
#    1:   string delimiter between arguments 2-n
#    2-n: file(s) to cat out
for arg in ${@:2} # $@ is the array of arguments, ${@:2} slices it starting at 2.
do
   cat $arg
   echo $1
done

この場合、ファイル名をcatに渡しています。しかし、明示的にデータの書き込みや書き換えを行わずにファイル内のデータを変換したい場合は、ファイルの内容を変数に格納することもできます。

file_contents=$(cat $filename)
[...do some stuff...]
echo $file_contents >> $new_filename

Stdinから読む

標準入力から読む限り、ほとんどのシェルにはかなり標準的なread組み込みがありますが、プロンプトの指定方法には違いがあります(少なくとも)。

Bash組み込みのmanページ にはreadのかなり簡潔な説明がありますが、 Bash Hackers ページ。

単に:

read var_name

複数の変数

複数の変数を設定するには、readに複数のパラメータ名を指定するだけです。

read var1 var2 var3

readはstdinから各変数に1つのWordを置き、残りのすべての単語を最後の変数にダンプします。

λ read var1 var2 var3
thing1 thing2 thing3 thing4 thing5
λ echo $var1; echo $var2; echo $var3
thing1
thing2
thing3 thing4 thing5

変数より少ない単語が入力された場合、残りの変数は空になります(以前に設定されていても)。

λ read var1 var2 var3
thing1 thing2
λ echo $var1; echo $var2; echo $var3
thing1
thing2
# Empty line

プロンプト

私はプロンプトに-pフラグをよく使います。

read -p "Enter filename: " filename

注:ZSHとKSH(そしておそらく他のもの)はプロンプトに異なる構文を使用します。

read "filename?Enter filename: " # Everything following the '?' is the Prompt

デフォルト値

これは本当にreadのトリックではありませんが、私はreadと組み合わせてそれをよく使用します。例えば:

read -p "Y/[N]: " reply
reply=${reply:-N}

基本的に、変数(reply)が存在する場合はそれ自身を返しますが、空の場合は次のパラメータ( "N")を返します。

4
Jacob Hayes

既にこのように振舞っている他の何かを使う(または連鎖させる)、そして"$@"を使う

たとえば、テキスト内のスペースの実行をタブに置き換えるツールを作成したいとしましょう。

trはこれを行うための最も明白な方法ですが、のみがstdinを受け入れるので、catからチェーニングする必要があります。

$ cat entab1.sh
#!/bin/sh

cat "$@"|tr -s ' ' '\t'
$ cat entab1.sh|./entab1.sh
#!/bin/sh

cat     "$@"|tr -s      '       '       '\t'
$ ./entab1.sh entab1.sh
#!/bin/sh

cat     "$@"|tr -s      '       '       '\t'
$ 

使用されているツールがすでにこのように動作する例では、代わりにsedを使用してこれを再実装できます。

$ cat entab2.sh
#!/bin/sh

sed -r 's/ +/\t/g' "$@"
$ 
3
Aaron Davies

次のこともできます。

#!/usr/bin/env bash

# Set variable input_file to either $1 or /dev/stdin, in case $1 is empty
# Note that this assumes that you are expecting the file name to operate on on $1
input_file="${1:-/dev/stdin}"

# You can now use "$input_file" as your file to operate on
cat "$input_file"

Bashでもっときちんとしたパラメータ置換のトリックについては、 this をご覧ください。

3
Daniel

最も簡単な方法およびPOSIX準拠は次のとおりです。

file=${1--}

これは${1:--}と同等です。

それからいつものようにファイルを読みます。

while IFS= read -r line; do
  printf '%s\n' "$line" # Or: env POSIXLY_CORRECT=1 echo "$line"
done < <(cat -- "$file")
0
kenorb

あなたはそれを単純にしてこのコードを使うこともできます


このコードでスクリプトファイルpass_it_on.shを作成すると、

#!/bin/bash

cat

走れます

cat SOMEFILE.txt | ./pass_it_on.sh

そしてstdinのすべての内容は単に画面に吐き出されるでしょう。


あるいは、このコードを使用してstdinのコピーをファイルに保存し、それを画面に吐き出すこともできます。

#!/bin/bash

tmpFile=`mktemp`
cat > $tmpFile
cat $tmpFile    

そしてここにもう一つの例があります。

http://mockingeye.com/blog/2013/01/22/reading-everything-stdin-in-a-bash-script/

#!/bin/bash

VALUE=$(cat)

echo "$VALUE"

楽しむ。

RaamEE

0
RaamEE