次のようなデータを出力するシェルスクリプトがあります。
1234567890 *
1234567891 *
最後の3文字「*」を削除する必要があります。私はそれを介してそれを行うことができることを知っています
(whatever) | sed 's/\(.*\).../\1/'
しかし、速度を上げるためにsedを使いたくありません。常に最後の3文字と同じになります。
出力をクリーンアップする簡単な方法はありますか?
すべてのデータが例のようにフォーマットされていると仮定すると、「 cut 」を使用して最初の列のみを取得します。
cat $file | cut -d ' ' -f 1
または最初の10文字を取得します。
cat $file | cut -c 1-10
以下は、sed OR awk ...
> echo 987654321 | rev | cut -c 4- | rev
987654
「カット」を使用した以前の例とは異なり、これは行の長さの知識を必要としません。
このタスクでは、bash
だけではsed
より速くなることはありません。 bash
で外部プロセスを起動することは、一般的には悪い考えですが、頻繁に行う場合のみです。
したがって、入力のeach行に対してsed
プロセスを開始している場合は、心配です。しかし、あなたは違います。 onesed
を開始するだけで、すべての作業が自動的に行われます。
ただし、次のsed
がお使いのバージョンより少し高速になる場合があります。
(whatever) | sed 's/...$//'
これは、行全体を短いバージョンで置き換えるのではなく、各行の最後の3文字を削除するだけです。現在、より最新のREエンジンでコマンドを最適化できるかもしれませんが、なぜリスクを取るのでしょう。
正直に言うと、私がそれがより速くなると考えることができる唯一の方法については、あなた自身のCベースのフィルタープログラムを手作りすることです。 mayがsed
よりも高速である唯一の理由は、処理の必要性に関する追加の知識を活用できるためです(sed
は一般化を許可する必要があります)そのため、行列は遅くなる可能性があります)。
最適化のマントラを忘れないでください:"測定、推測しないでください!"
実際にbash
で一度に1行ずつ実行したい場合(そして、それは悪い考えだと私は主張します)、次のように使用できます:
pax> line=123456789abc
pax> line2=${line%%???}
pax> echo ${line2}
123456789
pax> _
また、実際に必要速度が向上したかどうかを調べることもできます。行を1つの大きな塊として処理すると、sed
が非常に高速であることがわかります。次を入力します。
#!/usr/bin/bash
echo This is a pretty chunky line with three bad characters at the end.XXX >qq1
for i in 4 16 64 256 1024 4096 16384 65536 ; do
cat qq1 qq1 >qq2
cat qq2 qq2 >qq1
done
head -20000l qq1 >qq2
wc -l qq2
date
time sed 's/...$//' qq2 >qq1
date
head -3l qq1
実行します。これが私の(まったく高速ではない)R40ラップトップの出力です。
pax> ./chk.sh
20000 qq2
Sat Jul 24 13:09:15 WAST 2010
real 0m0.851s
user 0m0.781s
sys 0m0.050s
Sat Jul 24 13:09:16 WAST 2010
This is a pretty chunky line with three bad characters at the end.
This is a pretty chunky line with three bad characters at the end.
This is a pretty chunky line with three bad characters at the end.
これは1秒未満で20,000行であり、1時間に1回しか実行されない処理に適しています。
$ x="can_haz"
$ echo "${x%???}"
can_
awk
とsed
はどちらも非常に高速ですが、重要だと思われる場合は、次のいずれかを使用してください。
削除する文字が常に文字列の末尾にある場合
echo '1234567890 *' | tr -d ' *'
文字列内の任意の場所に表示でき、最後にあるもののみを削除する場合
echo '1234567890 *' | rev | cut -c 4- | rev
すべてのコマンドのmanページで、何が起こっているのかが説明されます。
ただし、sed
を使用する必要があると思います。
試すことができます
(whatever) | while read line; do echo $line | head --bytes -3; done;
head
自体はsed
やcut
よりも高速である必要があります。これは、正規表現や区切り文字の一致がないためですが、各行ごとにを個別に呼び出すとおそらくそれよりも重要です。
注:この回答は冗談を意図していますが、実際には機能します...
#!/bin/bash
outfile="/tmp/$RANDOM"
cfile="$outfile.c"
echo '#include <stdio.h>
int main(void){int e=1;char c;while((c=getc(stdin))!=-1){if(c==10)e=1;if(c==32)e=0;if(e)putc(c,stdout);}}' >> "$cfile"
gcc -o "$outfile" "$cfile"
rm "$cfile"
cat somedata.txt | "$outfile"
rm "$outfile"
cat somedata.txt
を別のコマンドに置き換えることができます。
スクリプトが常に10文字の行に3文字の余分な行を出力する場合(つまり、最初の10文字だけが必要な場合)は、次のように使用できます。
script | cut -c 1-10
不確実な数の非スペース文字が出力され、その後にスペースが続き、さらに2つの余分な文字(つまり、最初のフィールドだけが必要)が出力される場合、次を使用できます。
script | cut -d ' ' -f 1
...前のmajhoolのコメントのように。プラットフォームによっては、colrmもあります。これも、行が固定長の場合に機能します。
script | colrm 11
別の答えは、最後から3番目の文字がスペースであることに依存しています。これは、その位置の(ほぼ)すべての文字で機能し、「sedやPerlなどを使用せずに」実行します。
while read -r line
do
echo ${line:0:${#line}-3}
done
行が固定長の場合、echo
を次のように変更します。
echo ${line:0:9}
または
printf "%.10s\n" "$line"
しかし、これらはそれぞれdefinitelymuchsed
より遅い。
カットや魔法は必要ありません。bashでは次のように文字列をカットできます。
ORGSTRING="123456"
CUTSTRING=${ORGSTRING:0:-3}
echo "The original string: $ORGSTRING"
echo "The new, shorter and faster string: $CUTSTRING"
http://tldp.org/LDP/abs/html/string-manipulation.html を参照してください
スペースがない場合(またはスペースがある場合は区切り文字を変更する場合)は、最初の「フィールド」を印刷するためだけにawkを使用できます。
上記のフィールドをファイルに入れてこれを行いました
awk '{ print $1 }' < test.txt
1234567890
1234567891
それが良いかどうかはわかりません。
速度を上げるためにsed/awkを使いたくないのはどういうことですか? sed/awkは、ファイルを処理するためのシェルのwhile読み取りループよりも高速です。
$ sed 's/[ \t]*\*$//' file
1234567890
1234567891
$ sed 's/..\*$//' file
1234567890
1234567891
バッシュシェル付き
while read -r a b
do
echo $a
done <file