web-dev-qa-db-ja.com

同じ行の複数の変数をエコーする

同じ行に2つの変数をエコーし​​ます。
2015-03-04.01.Abhi_Ram.txtを変数FILENAMEに保存し、変数COUNTに10を保存して、同時にエコーしたいです。

Sample.txt

2015-03-04.01.Abhi_Ram.txt 10
2015-03-04.02.Abhi_Ram.txt 70

以下は私が思いついたコードです:

for line in `hadoop fs -cat sample.txt`
do

VAR="${line}"
FILENAME=`echo ${VAR}|awk '{print $1}'`
COUNT=`echo ${VAR}|awk '{print $2}'`
COUNT_DT=`date "+%Y-%m-%d %H:%M:%S"`
echo db"|"Abhi_Ram"|"record_count"|"${FILENAME}"||"${COUNT}"||"${COUNT_DT} >> output.txt
done

I want the output as:

db | Abhi_Ram | record_count | 2015-03-04.01.Abhi_Ram.txt || 10 || timestamp db | Abhi_Ram | record_count | 2015-03-04.02.Abhi_Ram.txt || 70 || timestamp

I'm getting the output as:

db | Abhi_Ram | record_count | 2015-03-04.01.Abhi_Ram.txt |||| timestamp
db | Abhi_Ram | record_count | 10 |||| timestamp
db | Abhi_Ram | record_count | 2015-03-04.02.Abhi_Ram.txt |||| timestamp
db | Abhi_Ram | record_count | 70 |||| timestamp

誰かが私に欠けているものを私に指摘できますか?

6
AS0207

考慮してください:

_while read filename count
do
    count_dt=$(date "+%Y-%m-%d %H:%M:%S")
    echo "db|Abhi_Ram|record_count|${filename}||${count}||${count_dt}"
done <sample.txt >>output.txt
_

これにより、ファイルが生成されます。

_$ cat output.txt 
db|Abhi_Ram|record_count|2015-03-04.01.Abhi_Ram.json||10||2015-08-10 14:42:39
db|Abhi_Ram|record_count|2015-03-04.02.Abhi_Ram.json||70||2015-08-10 14:42:39
_

ノート:

  1. シェル変数には小文字または大/小文字混合を使用するのがベストプラクティスです。システムは大文字の変数を使用するため、誤って変数を上書きすることは望ましくありません。

  2. echoステートメント内の多くの二重引用符は不要でした。出力文字列全体を、1つの二重引用符で囲まれた文字列の中に含めることができます。

  3. ファイルを一度に1行ずつ読み取りたい場合は、_while read ... done <inputfile_構文を使用する方が安全です。 readステートメントにより、filenameおよびcount変数を簡単に定義することもできます。

  4. コマンド置換の場合、多くの人がバックティック形式よりも$(...)の形式を好みます。これは、(a)$(...)によってコマンド置換の開始と終了が視覚的に区別されるため、(b)$(...)フォームが適切にネストされ、(c)すべてのフォントが明確に表示されないためです通常のティックとは異なるバックティック。 (チェプナーに感謝します。)

  5. 効率化のため、_output.txt_へのリダイレクトはループの最後に移動されました。このようにして、ファイルは一度だけ開かれ、閉じられます。 (Charles Duffyに感謝します。)

  6. 個々のエントリごとに_count_dt_を更新する必要がない限り、ループの前に配置し、_sample.txt_が処理されるたびに1回だけ設定できます。最新バージョンのbash(Mac OSXなし)がある場合は、_count_dt_割り当てをネイティブのbashステートメントに置き換えることができます(ありがとう、Charles Duffy)(シェルアウトは不要です)。

    _printf -v count_dt '%(%Y-%m-%d %H:%M:%S)T'
    _
9
John1024

John1024はこれを正しく行う方法を説明しました。元のバージョンが機能しなかった理由を見てみたい。基本的な問題は、forがループではなくwordsでループすることです。ファイルには各行に2つの単語(ファイル名とカウント)があるため、1行に2回ループを実行します。これを確認するには、次を試してください。

for line in `hadoop fs -cat sample.txt`
do
    echo "$line"
done

...次のように出力されます:

2015-03-04.01.Abhi_Ram.txt
10
2015-03-04.02.Abhi_Ram.txt
70

...これはあなたが望んでいるものではありません。また、入力ファイルに「*」という単語が含まれている場合、現在のディレクトリにファイル名のリストを挿入するなど、他の不快な癖もあります。

while read ... done <fileアプローチは、シェルスクリプト内の行を反復処理する正しい方法です。たまたまawk(この場合、read filename countを使用する)を台無しにすることなく、各行をフィールドに分割することもできます。

2
Gordon Davisson