ファイル名引数または標準入力からの入力を受け付けるスクリプトを書くにはどうすればよいでしょうか。
たとえば、less
をこのように使うことができます。 less filename
と同等にcat filename | less
を実行できます。
そうするための「箱から出して」簡単な方法はありますか?それともホイールを作り直して、スクリプトに少しロジックを書く必要がありますか?
ファイル引数がスクリプトの最初の引数である場合は、引数($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はキーボードから読み取ります。
read
は標準入力から読み込みます。ファイル(./script <someinput
)またはパイプ(dosomething | ./script
)を介してリダイレクトしても、動作が異なります。
あなたがしなければならないのはinputのすべての行をループすることです(そしてそれはfileの中の行を繰り返し処理するのと変わりません)。
(サンプルコード、1行のみ処理)
#!/bin/bash
read var
echo $var
標準入力の最初の行をエコーします(<
または|
を介して)。
最も簡単な方法はstdinを自分自身にリダイレクトすることです。
if [ "$1" ] ; then exec < "$1" ; fi
あるいはもっと簡潔な形式を好むなら:
test "$1" && exec < "$1"
今すぐあなたのスクリプトの残りの部分は標準入力から読み取ることができます。もちろん、ファイル名の位置を"$1"
としてハードコーディングするのではなく、より高度なオプション解析でも同様に実行できます。
どのシェルを使用するつもりなのか言及していないので、bashを想定します。ただし、これらはシェル全体で非常に標準的なものです。
引数は変数$1
-$n
を介してアクセスできます($0
はプログラムの実行に使用されたコマンドを返します)。たとえば、n個のファイルを区切り文字でcat
sするスクリプトがあるとします。
#!/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
標準入力から読む限り、ほとんどのシェルにはかなり標準的な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")を返します。
既にこのように振舞っている他の何かを使う(または連鎖させる)、そして"$@"
を使う
たとえば、テキスト内のスペースの実行をタブに置き換えるツールを作成したいとしましょう。
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' "$@"
$
次のこともできます。
#!/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 をご覧ください。
最も簡単な方法およびPOSIX準拠は次のとおりです。
file=${1--}
これは${1:--}
と同等です。
それからいつものようにファイルを読みます。
while IFS= read -r line; do
printf '%s\n' "$line" # Or: env POSIXLY_CORRECT=1 echo "$line"
done < <(cat -- "$file")
あなたはそれを単純にしてこのコードを使うこともできます
このコードでスクリプトファイル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