Есть ли способ показать в текстовом файле / скрипте только строки без комментариев? [дубликат]

Нет необходимости в chroot, я часто генерирую wot-карты / диаграммы из отдельной базы данных gpg, чем моя основная (например, рабочая группа). для этого экспорта GNUPGHOME

export GNUPGHOME=/mnt/home/naftuli
cd $GNUGPHOME
gpg --list-keys
19
17.01.2017, 12:54
7 ответов
grep -v "^#" your_file | grep -v "^$" | less

Удалите строки, начинающиеся с "#", а также удалите пустые строки, чем отправьте результат на less для лучшего отображения.

11
27.01.2020, 19:44

В случае сценариев 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
27.01.2020, 19:44

Просто grep никогда не сможет удалить все комментарии (или только комментарии), потому что grep не понимает язык, который он просматривает. Чтобы понять, что такое комментарий, а что нет, вам понадобится лексер , который понимает этот конкретный язык.

Есть несколько ответов на SO о том, как удалить все комментарии из определенных языков программирования. Я добавлю сюда два примера.

Для C ответ Джоша Ли утверждает:

gcc -fpreprocessed -dD -E test.c

Которая запускает препроцессор, но сохраняет макросы.

Для python ответ unutbu (с небольшой адаптацией мной) пишет небольшой лексический анализатор с использованием 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()))

Затем вы можете написать по одному из них для каждого языка программирования и использовать кейс. Предполагая, что лексер python называется 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

Дайте имя сценарию и добавьте лексеры для нужных / используемых языков . Это должна быть более или менее надежная конструкция для удаления комментариев из файлов разных типов. (Использование файла вместо регистра в именах файлов также было бы более надежным).

14
27.01.2020, 19:44

Ну, это зависит от того, что вы подразумеваете под комментариями. Если только строки без # , тогда может быть достаточно простого:

grep -v '#'

(но это вызовет такие строки, как echo '#' , как комментарий). Если строки комментариев - это строки , начинающиеся с с # , тогда вам может потребоваться:

grep -v '^#'

И если строки комментариев - это строки, начинающиеся с # после некоторого необязательного пробела, тогда вы можете использовать:

grep -v '^ *#'

И если формат комментария совсем другой, этот ответ вам не поможет.

25
27.01.2020, 19:44

Как упоминалось в комментариях выше, формат "комментариев" в вашем случае имеет значение. Тем не менее, для некоторых случаев этого может быть достаточно, без необходимости создавать скрипт.

Решение:

Читая вопрос, можно предположить, что вы уже используете grep для поиска файлов, так что передайте его через другой grep; примерно так:

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

Что не отлавливается:

Это все равно разрешит строки или строки, которые имеют символ "триггер" в другом месте строки, которые имеют комментарии в конце, как в echo "Hello World" # другой комментарий, или которые являются частью многострочного комментария (кроме случаев, отмеченных в объяснении ниже.

Если это используется в качестве пост-фильтра для grep, то эти ограничения должны быть незначительными, так как большинство комментариев будет отфильтровано, и вы больше не будете беспокоиться о том, "что ваши глаза остекленеют".

Объяснение:

Есть три шаблона, которые при необходимости можно модифицировать в соответствии с вашим случаем использования. Первый (?:^;) отлавливает строки, начинающиеся с символа ;. Должен быть первым, без пробелов. Второй отлавливает строки, начинающиеся с `/* ... */` в стиле комментария, с пробелами или без них. Третий отлавливает строки, начинающиеся с #, // или *, с пробелами или без них. * в последнем шаблоне помогает поймать строку внутри многострочного комментария в /* ... */, где обычно используется столбец * для соединения первой и последней строки вместе. Например:

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

Обозначение (? ... ) вокруг каждого шаблона делает их "не захватывающими" шаблонами, в надежде увеличить скорость и уменьшить потребление ресурсов. Аргументы -Pv в grep указывают ему использовать правила регулярных выражений Perl --perl-regexp, что позволяет группировать не захватывающие шаблоны и позволяет работать оператору чередования |, ни один из которых не работает в CLI grep. На странице руководства grep есть предупреждение, что опция -P является экспериментальной, поэтому проверьте ее, прежде чем использовать в своей системе. Опция --invert-match указывает grep на обратное соответствие, возвращая строки, которые не соответствуют шаблону. Их можно объединить и сократить до -vP.

Причина использования этого фильтра в качестве постфильтра к обычному grep заключается в трех моментах. Во-первых, вы можете делать обычную выборку и добавлять дополнительную работу по использованию этого фильтра только тогда, когда вы столкнетесь с проблемой слишком большого количества комментариев в выводе. (Меньше ввода и меньше используемых ресурсов). Во-вторых, вы, вероятно, уже разработали шаблоны, которые часто используете, и привычки, которые с ними связаны, и добавление дополнительных сложностей может их нарушить. Добавление дополнительной работы по отладке паттернов, когда в этом нет необходимости, является напрасной работой. В-третьих, он не очень хорошо работает с многострочными комментариями, но если вы уже искали в файле то, что вам нужно, то он удалит большинство, если не все, комментарии из результатов и послужит вашей цели.

3
27.01.2020, 19:44

Вот простой процесс удаления комментариев, т.е. все идет после '#' с использованием 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
27.01.2020, 19:44

Чтобы сделать это для 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.

3
27.01.2020, 19:44

Теги

Похожие вопросы