2016-07-01 4 views
0

に私は、ファイル内のテキストを変換し、かなりの長さのコマンドを書いています。このスクリプトは一連のパイプとして正しく動作しますが、私はそれを分解して一度に1つずつ変換するのに問題があります。格納したファイルの処理ステージはバッシュ

私はもともとのように各段階で変数を設定しようとした:

CONTENT=$(grep -o '^[^#]*' $1) 
SEGMENTS=$($CONTENT | grep ':') 

が、取得保管:長すぎる

コマンド:


を私もにそれを解散サブシェル(私はそれが彼らの名前だと思う):

CONTENT=(grep -o '^[^#]*' $1) 

そして私はecho $CONTENTは、コマンドではなく、テキストを印刷することを見たので、私は私が考えていたことができます: `近い

SEGMENTS=($CONTENT | grep ':') 

パースエラー|」

CONTENT=$(grep -o '^[^#]*' $1) 
SEGMENTS=(cat <($CONTENT) | grep ':') 

をしかし、それはどちらか動作していないようでした:


私も試してみました。

本当に長い文字列の文字列を読みやすい形式に分割するにはどうすればよいですか?あなたの助けをありがとう!

+1

あなたは-o 'コンテンツは= $(grepをしたい「^ [^#]を*」「$ 1 ");セグメント= $(エコー "$コンテンツ" | grep ':') '。または単に 'segments = $(grep -o '^ [^#] *'" $ 1 "| grep ':')'です。 '$ CONTENT | grep ':' 'は' $ CONTENT'の値をコマンドとして実行しようとします。将来、 'set -x'とhttp://www.shellcheck.netはあなたの友人です。 – Biffen

+0

ブリリアント。それは動作します、ありがとう! –

+0

ところで、あなたの多段階バージョンは実際に実行するのが遅く、効率も悪いです。シェルパイプラインは、次のプロセスを開始する前に最初のフェーズを完了させるのではなく、すべてを一度に実行します。 –

答えて

1

リテラルの答えは次のようになりますこれは:

#!/bin/bash 
#  ^^^^- needed for herestrings (the <<< syntax) 

content=$(grep -o '^[^#]*' <file.txt) 
segments=$(grep ':'  <<<"$content") 
fields=$(cut -d ':' -f1 <<<"$segments") 
uniq_fields=$(uniq   <<<"$fields") 
result=$(gcut -d '/' -f1,3 --output-delimiter=$'\t') 

これらのステージは、代わりに次のように表示されることがあります。

segments=$(printf '%s\n' "$content" | grep ':') 

はしかし、それをしないでください:それは非常に非効率的だし、そのため、あなたの元のコードよりもはるかに多くのメモリを使用して並列に実行することができない(とあなたの入力ファイルが重大なサイズのものである場合に実行する時間がかかります)。


あなたの目標は、検査を許可し、次のようなものを検討している場合:

grep -o '^[^#]*' file.txt | tee without_comments.txt \ 
    | grep ':'    | tee colons_only.txt \ 
    | cut -d ':' -f1  | tee fields_only.txt \ 
    | uniq     | tee fields_uniq.txt \ 
    | gcut -d '/' -f1,3 --output-delimiter=$'\t' 

...あなたは、各ステージに別々の出力が得られます。それとも、あなたは、開発と生産モードの間で変更する必要はありませんコードを望んでいた場合は、機能の使用を検討:

set -o pipefail # prevent presence of a pipeline from changing exit status 

logging() { 
    filename=$1; shift 
    if [ -n "$logdir" ]; then 
    "[email protected]" | tee -- "$logdir/$filename" 
    else 
    "[email protected]" 
    fi 
} 

logging  without_comments.txt grep -o '^[^#]*' file.txt \ 
    | logging colons_only.txt  grep ':' \ 
    | logging fields_only.txt  cut -d ':' -f1 \ 
    | logging fields_uniq.txt  uniq \ 
    | gcut -d '/' -f1,3 --output-delimiter $'\t' 

...変数logdirが空である場合にのみログ思われます。


私は、代わりにawkを使用することをお勧めします。以下ははるか、より効率的になり、そしてそれは同様に、より読みやすいと判断される引数があります:

awk ' 
    BEGIN { IFS=":"; OFS="\t"; } # split input on :s, combine output with tabs 
    /#/ { gsub(/#.*/, "") }   # remove comments 
    /:/ { seen[$1]++ }    # put field 1 of each line with a : into a map 
    END { 
    for (i in seen) { 
     split($1, pieces, "/")  # split each map key on "/"s 
     print pieces[0], pieces[2] # and put the 1st and 3rd in output 
    } 
    } 
' 
1

あなたが探しているすべての可読性の場合は、単に改行を追加します。

grep -o '^[^#]*' file.txt | 
grep ':' | 
cut -d ':' -f1 | 
uniq | 
gcut -d '/' -f1,3 --output-delimiter=$'\t' 

あなたも、|シンボルを揃えるとコメントを追加することができます。

grep -o '^[^#]*' file.txt | # Find the lines 
grep :     | # use grep and cut instead 
cut -d : -f1    | # of awk for no particular reason 
uniq      | # remove duplicates 
gcut -d '/' -f1,3 --output-delimiter=$'\t' 
関連する問題