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

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

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

jimmij
источник
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

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

Это сработало для меня

sed -i.old -E  "/^(#.*)$/d" file 
Дэвид Окви
источник
Это не справится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

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

bviktor
источник
1
.*$в первом регулярном выражении нет особого смысла - привязка бесполезна, и вы не захватываете сопоставленный текст для замены. использовать только^\s*
Джефф Шаллер
Это не справитсяprint "#tag" # Print a hashtag.
Рэй Баттерворт
0

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

sed '/^[[:blank:]]*#/d;s/#.*//;/^$/d'
Пьер-Damien
источник
-1

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

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

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

jackbmg
источник
Это не справитсяprint "#tag" # Print a hashtag.
Рэй Баттерворт
Ах, да ... конечно. Спасибо что подметил это. Я искал ответ относительно типичных файлов конфигурации linux, таких как pam.d config, поэтому я не думал об этом. Я думаю, что он должен быть адаптирован для поиска и удаления любых комментариев, которые лежат в той же строке, что и код. Я только что видел, вероятно, лучшее решение моей конкретной проблемы выше: egrep -v "# | $ ^"
jackbmg