ファイルの最後に空白行があるファイルがあります。grep
スクリプトで変数として渡されるファイル名を使用して、ファイルの最後にある空白行の数を数えるのに使用できますか?
grep
、私の本の中で純粋さのために@MichaelJohnの勝利を求めました。
ファイルの最後に空白行があるファイルがあります。grep
スクリプトで変数として渡されるファイル名を使用して、ファイルの最後にある空白行の数を数えるのに使用できますか?
grep
、私の本の中で純粋さのために@MichaelJohnの勝利を求めました。
回答:
空白行が最後にのみある場合
grep -c '^$' myFile
または:
grep -cx '' myFile
grep -cv . myFile
それを書く別の方法です(コードゴルファー向け)。しかしgrep
、ファイル内のどこかに空の行がある場合の解決策を見つけました。
grep -cv .
有効な文字を形成しないバイトのみを含む行もカウントします。
楽しみのために、いくつかの不気味なsed
:
#!/bin/sh
sed '/./!H;//h;$!d;//d;x;s/\n//' "$1" | wc -l
説明:
/./
任意の文字で行をアドレス指定するため、/./!
空でない行をアドレス指定します。それらの場合、H
コマンドはそれらをホールドスペースに追加します。したがって、空の各行についてホールドスペースに1行追加した場合、空の行の数よりも常に1行多くなります。後で気にします。//h
空のパターンは最後の正規表現と一致します。これは任意の文字でした。そのため、空ではない行はコマンドによってアドレス指定されてホールドスペースに移動しh
、収集された行を1に「リセット」します。次の空の行が追加されると、予想通り、再び2つあります。$!d
最後の行以外は出力せずにスクリプトを停止するため、以降のコマンドは最後の行の後にのみ実行されます。したがって、ホールドスペースに収集した空の行はすべてファイルの最後にあります。良い。//d
:d
空でない行に対してのみコマンドが再度実行されます。したがって、最後の行が空でなければ、sed
何も出力されずに終了します。ゼロ線。良い。x
交換はスペースとパターンスペースを保持するため、収集されたラインはパターンスペースにあり、処理されます。s/\n//
。wc -l
。さらにいくつかのGNU tac
/ tail -r
オプション:
tac file | awk 'NF{exit};END{print NR?NR-1:0}'
または:
tac file | sed -n '/[^[:blank:]]/q;p' | wc -l
以下の出力に注意してください。
printf 'x\n '
つまり、最後の完全な行の後に余分なスペースがある場合(一部は余分な空白行と見なすことができますが、POSIXのテキスト定義では有効なテキストではありません)、それらは0になります。
POSIXly:
awk 'NF{n=NR};END{print NR-n}' < file
しかし、これはファイルを完全に読み取ることを意味します(tail -r
/ tac
はシーク可能なファイルの最後からファイルを逆方向に読み取ります)。それは1
の出力を与えますprintf 'x\n '
。
あなたが実際にgrep
解決策を求めているので、私はこれをGNUにのみ依存するものを追加しますgrep
(そうです、シェル構文も使用していますecho
...):
#!/bin/sh
echo $(( $(grep -c "" "$1") - $(grep -B$(grep -cv . "$1") . "$1" |grep -c "") ))
私はここで何をしているんだ?$(grep -c ".*" "$1")
ファイル内のすべての行を数え、最後の空行を除いてファイルを減算します。
そして、それらを取得する方法?$(grep -B42 . "$1"
空でないすべての行とその前の42行をすべてgrepするため、空でない行の前に連続する空の行が42行を超えない限り、最後の空でない行まですべてが出力されます。この制限を回避するために、空行の総数であるオプション$(grep -cv . "$1")
のパラメーターとして、-B
常に十分な大きさをとっています。このようにして、末尾の空の行を取り除き、行の|grep -c ".*"
カウントに使用できます。
素晴らしいですね。(-;
tac | grep
、最初の非空白文字に-m -A 42
、次にマイナス1にすることです。どちらがより効率的wc -l | cut -d' ' -f1
かはわかりませんが、空白行をgrepする代わりにできますか?
tac
、wc
そしてcut
、しかし、ここで私はに自分自身を制限しようとしましたgrep
。あなたはそれを倒錯と呼ぶことができます、私はそれをスポーツと呼びます。(-;
別のawk
ソリューション。このバリエーションk
は、非空白行があるたびにカウンターをリセットします。次に、すべての行がカウンターを増分します。(つまり、最初の空白でない長さの行の後k==0
。)最後に、カウントした行数を出力します。
データファイルを準備する
cat <<'X' >input.txt
aaa
bbb
ccc
X
サンプルの末尾の空白行を数える
awk 'NF {k=-1}; {k++}; END {print k+0}' input.txt
3
この定義では、空白行にはスペースまたは他の空白文字が含まれる場合があります。それはまだ空白です。空白行ではなく空行を実際にカウントする場合は、に変更NF
し$0 != ""
ます。
$0 > ""
?使用するstrcoll()
よりも効率が低いであろう$0 != ""
その用途memcmp()
多くの実装(POSIXを使用することを必要とするために使用されるにstrcoll()
かかわらず)。
$0 > ""
違うかもしれないとは考えていません$0 != ""
。私は治療のために傾向があるawk
私は、入力や処理などの大きなデータセットを持って知っていれば時間が重要である、私は量削減に何ができるかがわかりますよう(とにかく「遅い」演算子としてawk
処理しなければならないが- I grep | awk
このような状況で構造体を使用しています。)ただし、POSIXの定義と思われるものをざっと見てみると、strcoll()
またはのいずれも参照できませんmemcmp()
。何が欠けていますか?
strcoll()
== 文字列は、ロケール固有の照合シーケンスを使用して比較されます。前の版と比較してください。私はそれを育てた人でした。参照してくださいaustingroupbugs.net/view.php?id=963
a <= b && a >= b
は、必ずしもと同じではない実装a == b
です。痛い!
awk
またはbash
(そのため[[ a < b ]]
のインスタンスのためのGNUシステム上EN_US.UTF-8ロケールでオペレータ)①
対②
(のインスタンスのためbash
のどれも、<
、>
、=
それらのためにtrueを返します)。おそらくそれは、よりbashの/ awkではよりも、これらのロケールの定義にバグです
ファイルの最後にある連続する空白行の数を数える
固体awk
+ tac
ソリューション:
サンプルinput.txt
:
$ cat input.txt
aaa
bbb
ccc
$ # command line
アクション:
awk '!NF{ if (NR==++c) { cnt++ } else exit }END{ print int(cnt) }' <(tac input.txt)
!NF
-現在の行が空であることを確認します(フィールドがない)NR==++c
-空白行の連続した順序を確保します。(NR
-レコード番号、++c
-均等にインクリメントされた補助カウンター)cnt++
- 空白行のカウンター出力:
3
IIUC、呼び出される次のスクリプトcount-blank-at-the-end.sh
は仕事をするでしょう:
#!/usr/bin/env sh
count=$(tail -n +"$(grep . "$1" -n | tail -n 1 | cut -d: -f1)" "$1" | wc -l)
num_of_blank_lines=$((count - 1))
printf "%s\n" "$num_of_blank_lines"
使用例:
$ ./count-blank-at-the-end.sh FILE
4
私はそれをテストしGNU bash
、Android mksh
そして中ksh
。
代替Python
ソリューション:
サンプルinput.txt:
$ cat input.txt
aaa
bbb
ccc
$ # command line
アクション:
python -c 'import sys, itertools; f=open(sys.argv[1]);
lines=list(itertools.takewhile(str.isspace, f.readlines()[::-1]));
print(len(lines)); f.close()' input.txt
出力:
3
https://docs.python.org/3/library/itertools.html?highlight=itertools#itertools.takewhile