解決策を探しましたが、この特定の問題(Googleに入力する必要がある単語が多すぎる)に対する解決策を見つけるのは少し難しいです。
したがって、次のデータを含むファイルがあります(関連のないデータは省略されます)。
... ... 2014年1月1日 ... ... ... ... ... 2014年1月2日 ... ... ... (...) ... ... 2014年3月1日 ... ... ... (...)
データが日付別にソートされていると想定できます。それで私がやりたかったことの1つが月の範囲に合うラインをキャプチャすることでした。たとえば、範囲が2月から4月までの場合は、月の列に、およびを含むFeb
すべての行を取得したいと思います。Mar
Apr
問題を明示せずに要求を少し抽象化するために、特定のパターンに一致する最初の行を取得し、他のパターンが最後に表示されるまで、その時点からすべての行をキャプチャしたいと思います。特定のパターンが一緒にグループ化されます)。
またはを使用して、同様の問題に対するいくつかの解決策を見つけましたgrep
。この状況では、どちらが最善かわかりません。sed
awk
これはすべてbashスクリプトで行われるので、すべての月"コード"を含む配列[ Jan
、、、、 ... Feb
]Mar
を持って、私が望む範囲にあるかどうかを確認しようとしました。この問題に対するよりエレガントな解決策になります。
編集: @jasonwryan まあ、実際にスクリプトに範囲を指定したので、 './script.sh --month "Jan, Apr"'はデータファイルを毎月ソートしてからすべての範囲をgrepできる必要があります(この場合は1 〜4月)。したがって、awk '/Feb|Apr|May/'はこの場合は機能しますが、2月から11月までを望む場合は異なります(awk '/Feb|Mar|Apr|May|Jun|Jul|Aug |Sept| 11/'ファイル)。したがって、任意の範囲に基づいて自動化することは困難です。また、月に1回以上(毎日利用可能)のキューが必要です。指定するのを忘れました。
答え1
mrng(){ sed "$(set -f;unset IFS rng l;n='
';[ -n "$ZSH_VERSION" ] && emulate sh
prng() for m do rng=${r%%"$m"*}${r##*"$m"} _l=$((_l+1))
printf "\n\n%s\n/$pat/{\n\t:$l.$_l\n\tn" $m
printf "\n\n%s\n\t/$pat/b$l.$_l.0" $rng
printf "\n\tb$l.$_l\n\t:$l.$_l.0\n}"
done
pat=$( printf %s "${1:-%m}$n"| sed -n 's/%/&&/g;l'|
sed ":n$n\$!N;s/\\\\\n//;tn${n}s/\$$//"); shift
r=$( locale -c LC_TIME|sed '4!d;y/;/ /')
for m do case $m in (-) rng=$r ;;
(-*) rng=${r%%"${m#-}"*}${m#-} ;;
(*-) rng=${m%-}${r##*"${m%-}"} ;;
(*-*) rng=${m%%-*}${r##*"${m%%-*}"} ;
case $rng in (*${m##*-}*)
rng=${rng%%"${m##*-}"*}${m##*-} ;;(*)
rng=$rng\ ${r%%"${m##*-}"*}${m##*-};;esac
;;esac; : $((l+=1))
prng ${rng:="$m"}; unset rng
done| sed " 1d;s/.*\(...\)\(\n\)\(.*[^%]\(%%\)*\)%m/\2\1\2\3\1/
/./!{N;N$n};/\n/D"
);d"
}
これはシェル関数です。この方法で呼び出すには、シェルスクリプトに適用するか、現在のシェルで評価する必要があります。次のように呼び出すことができます。
mrng "$pat" Jan-Mar Jun Sep-Nov <infile
-
また、次のようなオープンレンジも可能です。みんなまたはMar-
3月から12月まで。主張はそうではありません持つ範囲の指定 - 上記のようにすべてJun
です。
しかし、実際には月名をまったく解釈せず、locale
ユーティリティから収集します。(これは依存関係です)そして、現在のロケールで3文字の月名を使用して動作します。
実際には、ほぼすべての範囲でサラウンド範囲を実行できます。するサラウンド、またはおそらくより良い表現でとにかく蓄積してください。
最初の引数はsed
互換性のあるBREスキーマであると期待します。例外は、月名が出ると予想される場所ごとに使用する必要があることです%m
。 sを複数挿入することもできます%m
。Mar...Mar
- と同じ行だけを一致させたい場合でも、これを実行できますJun...Jun
。たぶんこれはあまり役に立たないかもしれませんが、おそらく…?
複雑に見えますが、その半分以上が引数解析のためのものです。sed
結局、比較的簡単です。たとえば、これを行うと:
mrng %m Dec-Jan
sed
...次のスクリプトが生成されます。
/Dec/{
:1.1
n
/Jan/b1.1.0
/Feb/b1.1.0
/Mar/b1.1.0
/Apr/b1.1.0
/May/b1.1.0
/Jun/b1.1.0
/Jul/b1.1.0
/Aug/b1.1.0
/Sep/b1.1.0
/Oct/b1.1.0
/Nov/b1.1.0
b1.1
:1.1.0
}
/Jan/{
:1.2
n
/Feb/b1.2.0
/Mar/b1.2.0
/Apr/b1.2.0
/May/b1.2.0
/Jun/b1.2.0
/Jul/b1.2.0
/Aug/b1.2.0
/Sep/b1.2.0
/Oct/b1.2.0
/Nov/b1.2.0
/Dec/b1.2.0
b1.2
:1.2.0
};d
...結局、多くのコードが生成され、ほとんどの場合評価されません。一般的な行では、Decと一致することを確認し、そうでなければJanと一致することを確認し、それ以外の場合は出力から削除します。
しかし、これらのパターンのいずれかと一致すると、単純な分岐ループが始まります。したがって、上記の例では、行がDecと一致すると印刷され、n
外部入力ラインで上書きされます。新しい行がランダム月と一致する場合しかし、12月、sed
b
牧草地のラベル:1.1.0
- これはラインがまだ評価されていないことを意味しますJan
。同様に処理されますが、どの月にも評価されません。今後12月を除いて一致する月がない場合は、ラベルsed
b
の上に移動して行を印刷して拡張子を引きます。:1.1
n
これにより、範囲の各月に対して-
上記のような関数(それぞれ固有のラベルが付いています)が生成されます。:
これは、コマンドライン引数が累積効果を持つことを意味します。いくつかの例:
printf %s\\n 'not a month' May 'not a month' 'also not a month' Apr |
m_rng %m Apr May
上記は次のとおりです。
May
not a month
also not a month
入力ではMay
前に来、コマンドラインでは後に来るからApr
です。Apr
しかし、これはやや粗雑な経験的方法です。入力はコマンドライン引数の順序で処理されますが、サイクル全体が完了すると処理が再開されます。
printf %s\\n 'not a month' May 'not a month' 'also not a month' Jun Apr |
m_rng %m Apr May
...印刷...
May
not a month
also not a month
Apr
ループが中断されるため、そのJun
行は削除され、次の入力行で処理が再び上から始まりますApr
。
とにかく、パターンには次のものを使用する必要があります。
mrng '^\([^ ]\{1,\} *\)\{3\}%m' [month args]