web-dev-qa-db-ja.com

テキストファイル/スクリプトでコメント化されていない行のみを表示する方法はありますか?

多くの場合、手動でファイルをgrepするときは、コメントが多すぎて目を凝らしてしまい、コメントのない行だけを表示するように表示できる方法がありたくありません。

猫や他のツールでコメントをスキップする方法はありますか?私は方法があると思います、それは正規表現を含みます。単に表示するだけで、実際には線などを削除しないでください。

コメントは#の形式で、xtermとしてzshを使用しています。

21
shirish

まあ、それはあなたがコメントで何を意味するかによって異なります。 #のない行だけの場合は、単純です:

grep -v '#'

十分かもしれません(ただし、これはecho '#'などの行をコメントと呼びます)。コメント行がstarting with #の場合、次のものが必要になる場合があります。

grep -v '^#'

また、コメント行が、オプションの空白の後に#で始まる行である場合は、次のように使用できます。

grep -v '^ *#'

また、コメントの形式がまったく異なる場合、この回答は役に立ちません。

18
Stephen Rauch

Grepが通過する言語を理解していないため、grepを実行してもすべてのコメント(またはコメントのみ)を削除することはできません。コメントと非コメントを理解するには、その特定の言語を理解するlexerが必要です。

特定のプログラミング言語からすべてのコメントを削除する方法についてSOにいくつかの回答があります。ここに2つの例を追加します。

[〜#〜] c [〜#〜]の場合 Josh Leeによる回答 は次のように主張します:

gcc -fpreprocessed -dD -E test.c

これはプリプロセッサを実行しますが、マクロは保持します。

pythonの場合 nutbuによる回答 (私自身による小さな適応)は、tokenizeを使用して小さなレクサーを書き込みます。

import tokenize
import io
import sys

def nocomment(s):
    result = []
    g = tokenize.generate_tokens(io.BytesIO(s).readline)  
    for toknum, tokval, _, _, _  in g:
        # print(toknum,tokval)
        if toknum != tokenize.COMMENT:
            result.append((toknum, tokval))
    return tokenize.untokenize(result)

print(nocomment(sys.stdin.read()))

次に、プログラミング言語ごとにこれらの1つを記述して、ケースを使用できます。 python lexerがremove-comments.pyと呼ばれると仮定します

#!/bin/sh
case "$1" in
  *.py)
    remove-comments.py < "$1"
    break
    ;;
  *.c|*.C|*.cc)
    gcc -fpreprocessed -dD -E "$1"
    break
    ;;
  *)
    echo I do not know how to remove comments from $1, sorry
    break
    ;;
esac

スクリプトに名前を付け、必要な言語のレクサーを追加/使用します。これは、さまざまな種類のファイルからコメントを削除するための多少堅牢な設計にする必要があります。 (ファイル名の大文字小文字の代わりにfileを使用すると、より堅牢になります)。

14
grochmal
grep -v "^#" your_file | grep -v "^$" | less

"#"で始まる行を削除し、空の行も削除してから、結果をlessに送信して表示を改善します。

8

bashスクリプトの場合、set -vnコマンドを使用して実行できます。 -vは、bashに冗長モードを開始するように指示します。このモードでは、読み取ったコマンドも出力されます。 -nは、何も実行せずにスクリプトファイルのみを読み取るようにbashに指示します。

例:

$ cat ./testscript.sh                                                                                                    
#!/bin/bash

# comment
set -vn
echo "Hello World" # another comment
$ ./testscript.sh                                                                                                        
echo "Hello World" # another comment

ご覧のとおり、#で始まる行は無視されますが、インラインコメントは引き続き出力されます。これはもちろん理想的ではありませんが、少なくともgrepなどの外部ツールは必要ありません。他のスクリプト言語のそのような機能は知りません

4

上記のコメントで述べたように、ユースケースでの「コメント」の形式は、違いを生みます。それでも、いくつかのケースでは、スクリプトを作成しなくてもこれで十分な場合があります。

ソリューション:

質問を読むと、とにかくファイルを検索するためにgrepをすでに使用していることが示唆されているので、パイプラインでanother grepにパイプします。このような:

grep your_pattern your_file | grep --Perl-regexp --invert-match '(?:^;)|(?:^\s*/\*.*\*/)|(?:^\s*#|//|\*)'

トラップされないもの:

これにより、行、または行のどこかに「トリガー」文字が含まれている、echo "Hello World" # another commentのように最後にコメントがある、または複数行コメントの一部である(説明に記載されている場合を除く)未満。

これをgrepのポストフィルターとして使用する場合、ほとんどのコメントはフィルターされ、「目が眩む」心配がなくなるため、これらの制限は無視できます。

説明:

3つのパターンがあり、必要に応じてユースケースに合わせて変更できます。最初の(?:^;)は、;文字で始まる行をキャッチします。空白なしで最初にする必要があります。 2番目のcatches lines that begin with the `/* ... */` comment style, with or without leading white space. The thirdは、先頭の空白の有無に関係なく、#//、または*で始まる行をキャッチします。最後のパターンの*は、/* ... */スタイルの複数行コメント内の行をキャッチするのに役立ちます。一般的なスタイルは*の列を実行して最初と最後の行を接続することです一緒。例えば:

/************
 *
 * This is my
 * multi-line
 * comment.
 *
 ************/

各パターンの周りの(? ... )表記は、それらを「キャプチャしない」パターンにします。うまくいけば、速度を上げ、リソース消費を減らすことができます。 grepの-Pv引数は、Perl正規表現ルール--Perl-regexpを使用するように指示します。これにより、非キャプチャグループ化が可能になり、|代替演算子が機能し、どちらもCLI grepでは機能しません。 grepのmanページでは、-Pオプションが実験的であることを警告しているため、システムで依存する前にテストしてください。 --invert-matchgrepに一致を元に戻すように指示し、パターンに失敗した行を返します。これらは組み合わせることができ、代わりに-vPに短縮できます。

これを通常のgrepのポストフィルターとして使用する理由は3つあります。まず、通常のgreppingを実行し、出力にコメントが多すぎるという問題が発生した場合にのみ、これを使用する追加の作業を追加します。 (タイピングが少なくなり、使用するリソースが少なくなります。)次に、一般的に使用するパターンと、それに伴う習慣をすでに開発している可能性があります。無駄な作業でなくても、パターンをデバッグするための作業を追加するのは無駄な作業です。第3に、複数行のコメントではうまくいかないが、必要なファイルをすでにgrepした場合は、結果からほとんどすべてのコメントが削除され、目的が果たされる。 。

3
user207673

これはコメントを削除する簡単なプロセスです。つまり、すべてはsedとawkを使用して「#」の後に来ます。

[root@master]# cat hash
This is a program to remove comments from this file
#!/bin/bash
# comment
set -vn # comment
echo "Hello World" # another comment
echo "testscript for removing comments"
echo "Hello World" # another comment
echo 'This is a # sign' #comment
echo "This is a # sign" #comment

[root@master]# awk -F '#' 'BEGIN{OFS="#";} { if (!/#/) ;else $NF="";print $0}' hash | sed -n 's/#$//g;p'
This is a program to remove comments from this file
set -vn
echo "Hello World"
echo "testscript for removing comments"
echo "Hello World"
echo 'This is a # sign'
echo "This is a # sign"
2
Aljo Antony

これをbash(またはbourne Shellファイル)に対して行うには、bashの「declare -f functionname」を利用できます。これにより、適切なインデントとコメントの削除の両方でfunctionnameが表示されます(コメントが削除されるので、ボーナスとして)インデントも良いでしょう):

BEAUTIFIER () {
  for f in "$@"; do
    printf "%s" "
      F_from_sh () {
        $(cat "$f")
      }
      echo ___ beautified version of $f : _________________
      declare -f F_from_sh | awk ' (NR > 2) && length>2' | sed -e 's/^  //'
    " | bash
  done
}

次に、次のように使用します。

BEAUTIFIER script1.sh  script2.bash  etc

注意:スクリプトのすべてのコメントが削除されます。「Shebang」の最初の行も削除されます。 $ fの最初の行を表示することもできます。

2
Olivier Dulac