Как я могу удалить все комментарии из файла?


21

У меня есть файл с комментариями:

foo
bar
stuff
#Do not show this...
morestuff
evenmorestuff#Or this

Я просто хочу напечатать весь некомментированный код:

foo
bar
stuff
morestuff
evenmorestuff

Возможность извлечения комментариев из файла очень важна ... Какой хороший способ сделать это?


1
Вы не можете удалить части строки с помощью grep. Вы можете использовать Sed для этого
чудо173

2
Ваш текст и ваш пример противоречат. Вы пишете о закомментированных строках, но ясно, что из последней строки вы имеете в виду части строк. Затем удаляется первая строка с комментарием, включая EOL, а вторая может быть, но неясно, так как это последняя строка. Пожалуйста, перефразируйте «закомментированные строки», чтобы быть точным, и устраните неоднозначность ваших примеров.
Энтон

5
попробуйте использовать awk -F\# '$1!="" { print $1 ;} '.
Архемар

2
Как будет echo '#' # output a #обрабатываться такая строка ?
Кусалананда

3
@Questionmark Я мог бы быть умным, но я не умный пишущий-грамматик-парсер.
Кусалананда

Ответы:


40

Один из способов , чтобы удалить все комментарии заключается в использовании grepс -oопцией:

grep -o '^[^#]*' file

где

  • -o: печатает только совпадающую часть строки
  • первый ^: начало строки
  • [^#]*: любой символ, кроме #повторяющегося ноля или более раз

Обратите внимание, что пустые строки тоже будут удалены, но останутся только строки с пробелами.


2
Я хотел бы использоватьgrep -v '^#' file > newfilewithoutcomments
Basile Starynkevitch

1
Следует отметить, что это НЕ общий метод для сценариев оболочки, так как, например, строка somvar='I am a long complicated string ## with special characters' # and I am a commentне будет обрабатываться правильно.
Wildcard

Этот вариант лучше работает для меня (на Mac):grep -o '^[^#].*' file
Pierz

Комментарии исчезли, но я вижу кучу пробелов на их месте в выводе? sedРешение имеет только одну пустую строку, кажется твердым аргументом для использования другого ответа, если я что-то упустил?
JBallin

@JBallin Ты определил псевдоним для, grepможет быть? Попробуйте изменить grepна command grep, если вы все еще видите пробелы после примера ввода.
Джимми

31

Я верю, что sedсправится с этим гораздо лучше, чем grep. Что-то вроде этого:

sed '/^[[:blank:]]*#/d;s/#.*//' your_file

объяснение

  • sedпо умолчанию будет смотреть на ваш файл построчно и печатать каждую строку после возможного применения преобразований в кавычках. ( sed '' your_fileпросто напечатает все строки без изменений).
  • Здесь мы даем sedдве команды для выполнения в каждой строке (они разделяются точкой с запятой).
  • Первая команда говорит: /^[[:blank:]]*#/d. В английском это означает, что если строка соответствует хешу в начале (которому предшествует любое количество ведущих пробелов), удалите эту строку (она не будет напечатана).
  • Вторая команда: s/#.*//. В английском, то есть, вместо хэш-метки следует столько вещей, сколько вы можете найти (то есть до конца строки) ничем (ничто не является пустым пространством между последними двумя //).
  • Таким образом, это будет проходить через строки удаления вашего файла, которые состоят целиком из комментариев, и любые оставшиеся после этого строки будут исключены из них.

1
Он также удалит все найденное после хеша внутри строки , нет? Например mystring="Hello I am a #hash" , станет mystring="Hello I am a"
Javadba

@javadba, да, но в этот момент вы могли бы также использовать полный анализатор. Что будут использовать эти данные, которые могут понимать кавычки и назначения переменных, но не могут обрабатывать комментарии? (Вот почему многие файлы конфигурации, такие как crontabразрешают только полнострочные комментарии с пробелом или без него, но не допускают конечные комментарии в строке. Логика НАМНОГО проще. Используйте только первую из двух инструкций Sed в этом ответе для зачистки комментариев crontab.)
Wildcard

отличный ответ, это выглядит как отличный баланс между полезностью и сложностью для широкого спектра общих вариантов использования, но в случае, если вы заранее знаете, что вам нужно только удалить строки, начинающиеся непосредственно с #(в столбце 1), есть ли польза для sedболее grep -v "^#"?
RBF06

4

Вы можете получить требуемый результат, используя команду sed. Команда ниже сделала трюк для меня.

sed 's/#.*$//g' FileName

где

  • #.*$- Regexp отфильтрует всю строку, которая начинается с #конца строки

Здесь нам нужно удалить эти строки, чтобы мы заменили их пустыми, пропустив часть «замена».

  • g упоминание повторного поиска шаблона, пока не будет достигнут конец файла.

Общий синтаксис sed: s/regexp/replacement/flags FileName


2
примечание: в этом случае 4-я строка заменяется новой.
αғsнιη

1
Попробуйте это с помощью сценария, содержащего эту sedкоманду ...
Кусалананда

Это не справитсяprint "#tag" # Print a hashtag.
Рэй Баттерворт

3

Как уже отмечали другие, sed и другие текстовые инструменты не будут работать хорошо, если какие-либо части скрипта выглядят как комментарии, но на самом деле это не так. Например, вы можете найти # внутри строки, или довольно распространенный $#и ${#param}.

Я написал средство форматирования оболочки под названием shfmt , в котором есть функция минимизации кода. Это включает в себя удаление комментариев, среди прочего:

$ cat foo.sh
echo $# # inline comment
# lone comment
echo '# this is not a comment'
[mvdan@carbon:12] [0] [/home/mvdan]
$ shfmt -mn foo.sh
echo $#
echo '# this is not a comment'

Синтаксический анализатор и принтер являются пакетами Go, поэтому, если вам нужно нестандартное решение, довольно легко написать программу Go из 20 строк, которая удалит комментарии именно тем способом, который вам нужен.


2

Вы можете использовать обратное совпадение следующим образом:

    #grep -v "#" filename

-v, --invert-match Инвертировать смысл соответствия, чтобы выбрать несовпадающие строки. (-v определяется POSIX.)


2
@alinh Спасибо за просмотр ответа. Обратите внимание, что вопрос требует не только начало строки, но и в любом месте файла. Это также показывает его / ее ожидаемый результат в вопросе выше. Мой ответ будет неверным, если я буду искать только начало строки.
Раза

ZZZ. мой плохой, не видел последней строки :(
alinh

1
Это полностью удалит строку, начинающуюся с evenmorestuffпримера OP.
Джозеф Р.

@JosephR. хороший улов. Я пропустил это раньше. В этом случае grep -o '^[^#]*' fileбудет лучшим решением. это уже объяснил Джимми. спасибо за ваш отзыв
Raza

Это не справитсяprint "#tag" # Print a hashtag.
Рэй Баттерворт

2

Мне нравится ответ Джозефа, но мне нужно было его удалить // комментарии, поэтому я немного изменил его и проверил на redhat

# no comments alias
alias nocom="sed -E '/^[[:blank:]]*(\/\/|#)/d;s/#.*//' | strings"

# example
cat SomeFile | nocom | less

Могу поспорить, что есть лучший способ удаления пустых строк, чем использование строк, но это было быстрое и грязное решение, которое я использовал.

-cheers


Это не справитсяprint "#tag" # Print a hashtag.
Рэй Баттерворт


1
cat YOUR_FILE | cut -d'#' -f1

Он использует в #качестве разделителя столбцов и сохраняет только первый столбец (это все, что раньше #).


1
Если YOUR_FILEэто скрипт, содержащий эти команды, он будет помещен cat YOUR_FILE | cut -'в файл в этой строке.
Кусалананда

1

Используйте выражение как

egrep -v "#|$^" <file-name> 

: -v: сделает обратное совпадение

: #: будет соответствовать всем строкам, начинающимся с #

: $ ^: будет соответствовать всем пустым строкам


1
Нет, в #любом месте строки совпадет и удалит всю строку.
ilkkachu

1

Лучшее решение было бы использовать команду:

sed -i.$(date +%F) '/^#/d;/^$/d' ntp.conf

-I - это редактирование на месте, но префикс, следующий сразу за ним, указывает sed создать резервную копию. В этом случае с расширением даты (ntp.conf.date) Мы запускаем две команды, каждая с адресным пространством, первая удаляет закомментированные строки, а вторая, отделенная от первой точкой с запятой, удаляет пустые строки.

Я нашел это решение на: theurbanpenguin.com


0

Похоже, что ни один из других ответов не делает этого должного, они либо оставляют пустыми строками, либо оставляют в строках, где комментарий не находится на первом символе. Я закончил тем, что использовал это:

cat << EOF >> ~/.bashrc
alias nocom='sed -e "/^\s*#/d" -e "/^\s*$/d"'
EOF

Это устанавливает псевдоним, так что вам не нужно запоминать его (что невозможно начать с). Откройте новый сеанс, и вы получите новую nocomкоманду. Тогда вы можете просто

nocom /etc/foobar.conf

Приветствия.


1
.*$в первом регулярном выражении нет особого смысла - привязка бесполезна, и вы не захватываете сопоставленный текст для замены. использовать только^\s*
Джефф Шаллер

Это не справитсяprint "#tag" # Print a hashtag.
Рэй Баттерворт

0

После второго ответа Джозефа Р. я добавляю /^$/dудалить пустую строку.

sed '/^[[:blank:]]*#/d;s/#.*//;/^$/d'

-1

Я публикую то, что работает для меня, и, кажется, имеет смысл, после прочтения других, с объяснениями. Пара постов подошла близко, но я пока не могу комментировать (потому что я новичок):

grep -E -v "(^#.*|^$)" filename
  • -E = интерпретировать следующий шаблон как регулярное выражение, похожее на использование egrep
  • -v = вывести инверсию шаблона (будут напечатаны строки, не соответствующие выражению)
  • "(^#.*|^$)"= это имеет канал, который обозначает оператор ИЛИ. Это выражение говорит, что нужно напечатать любую строку, которая начинается с #(и что-нибудь еще после него) ИЛИ любую строку с нулевым символом между началом и концом строки.

На -vэкране будет напечатана инверсия того, что будет любой строкой с символами, которая не начинается с #.


Это не справитсяprint "#tag" # Print a hashtag.
Рэй Баттерворт

Ах, да ... конечно. Спасибо что подметил это. Я искал ответ относительно типичных файлов конфигурации linux, таких как pam.d config, поэтому я не думал об этом. Я думаю, что он должен быть адаптирован для поиска и удаления любых комментариев, которые лежат в той же строке, что и код. Я только что видел, вероятно, лучшее решение моей конкретной проблемы выше: egrep -v "# | $ ^"
jackbmg
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.