リテラルの答えは次のようになりますこれは:
#!/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
}
}
'
あなたは-o 'コンテンツは= $(grepをしたい「^ [^#]を*」「$ 1 ");セグメント= $(エコー "$コンテンツ" | grep ':') '。または単に 'segments = $(grep -o '^ [^#] *'" $ 1 "| grep ':')'です。 '$ CONTENT | grep ':' 'は' $ CONTENT'の値をコマンドとして実行しようとします。将来、 'set -x'とhttp://www.shellcheck.netはあなたの友人です。 – Biffen
ブリリアント。それは動作します、ありがとう! –
ところで、あなたの多段階バージョンは実際に実行するのが遅く、効率も悪いです。シェルパイプラインは、次のプロセスを開始する前に最初のフェーズを完了させるのではなく、すべてを一度に実行します。 –