2

私はこの問題に悩まされています:私はシェルスクリプトを書きました.stdinから多くの行を含む大きなファイルを取得します.それが実行方法です:

./script < filename

スクリプト内の別の操作への入力としてファイルを使用したいのですが、このファイルの名前を変数に格納する方法がわかりません。
stdin からファイルを引数として取り、このファイル自体で awk 操作を行うスクリプトです。スクリプトで書くとします:

script:
#!/bin/sh
...
read file
...
awk '...' < "$file"
...

入力ファイルの最初の行のみを読み取ります。そして、私は次のように書く方法を見つけました:

Min=-1
while read line; do
    n=$(echo $line | awk -F$delim '{print NF}')   
    if [ $Min -eq -1 ] || [ $n -lt $Min ];then
    Min=$n
    fi
done

処理を待つのに非常に長い時間がかかります.awkはかなり時間がかかるようです. では、これを改善するにはどうすればよいでしょうか。

4

5 に答える 5

2

/dev/stdinここで非常に役立ちます。実際、これは入力への単なる一連のリンクです。

したがって、書き込みcat /dev/stdinはファイルからのすべての入力を提供し、入力ファイル名の使用をまったく拒否できます。

ここで質問に答えてください :) から始まるリンクを再帰的に読み取ると、/dev/stdinファイル名が得られます。バッシュコード:

r(){
    l=`readlink $1`
    if [ $? -ne 0 ]
    then
        echo $1
    else
        r $l
    fi
}
filename=`r /dev/stdin`
echo $filename

-fUPD: Ubuntu でreadlinkのオプションを見つけました。つまりreadlink -f /dev/stdin、同じ出力が得られます。このオプションは、システムによっては存在しない場合があります。

UPD2:tests (test.sh は上記のコードです):

$ ./test.sh <input # that is a file
/home/sfedorov/input
$ ./test.sh <<EOF
> line
> EOF
/tmp/sh-thd-214216298213
$ echo 1 | ./test.sh 
pipe:[91219]
$ readlink -f /dev/stdin < input 
/home/sfedorov/input
$ readlink -f /dev/stdin << EOF
> line
> EOF
/tmp/sh-thd-3423766239895 (deleted)
$ echo 1 | readlink -f /dev/stdin
/proc/18489/fd/pipe:[92382]
于 2013-10-31T10:56:00.197 に答える
2

あなたはこれをやり過ぎています。スクリプトを呼び出す方法:

  • ファイルの内容はスクリプトの標準入力です
  • スクリプトは引数を受け取りません

ただしawk、デフォルトですでに標準入力から入力を受け取るため、これを機能させるために必要なことは次のとおりです。

  • awkファイル名の引数を指定しないと、自動的にラッピング シェルの stdin になります。
  • ラッピング スクリプトがパーツに到達する前に、その入力を消費しないでawkください。具体的には: いいえread

awkスクリプトにそれだけがある場合は、呼び出しに還元されるため、それを完全に廃止してawk直接呼び出すことを検討してください。awkまたは、スクリプトを1 ではなく直接1 にしshます。

余談: while read line/multipleawkバリアント (問題のもの) が遅い理由はawk、入力の各行ごとにプロセスを生成し、プロセスの生成がawk単一行の処理よりも桁違いに遅いためです。generate tmpfile/single awkvariant (あなたの回答のも​​の) がまだ少し遅い理由は、tmpfile を行ごとに生成し、毎回追加するために再度開いているためです。

于 2013-10-31T05:19:27.580 に答える
0

入力ファイル名を引数として取り、スクリプト内のファイルから読み取るようにスクリプトを変更します。

$ ./script filename

script

filename=$1
awk '...' < "$filename"

スクリプトが標準入力から読み取るだけの場合、入力を提供する名前付きファイルがあるという保証はありません。パイプやネットワーク ソケットからの読み取りも同様に簡単です。

于 2013-10-31T13:48:01.353 に答える
0

スクリプトを別の方法で呼び出して、次のように YourFilename の標準出力を scriptName にパイプします (cat ファイル名の標準出力は、スクリプトへの標準入力になります。実際には、この場合は awk コマンドです。ファイル名 Names.data とスクリプト showNames があるため) .sh 次のように実行します

猫の名前.data | ./showNames.sh

ファイル名の内容 Names.data ハックルベリー フィン ジャック スプラット ハンプティ ダンプティ

scrip;t showNames.sh の内容

#!/bin/bash
#whatever awk commands you need
awk  "{ print }"
于 2013-10-31T15:52:56.400 に答える
-2

数秒かかりますが、最終的に私の問題を解決するこの方法を見つけました。

grep '.*' >> /tmp/tmpfile
Min=$(awk -F$delim 'NF < min || min == "" { min = NF };END {printmin}'</tmp/tmpfile)

stdin から読み取った後、tmpfile が入力ファイルと同じになるように、各行を一時ファイルに追加するだけです。

于 2013-10-31T22:12:07.017 に答える