Як я можу видалити всі коментарі з файлу?


21

У мене є файл із коментарями:

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

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

foo
bar
stuff
morestuff
evenmorestuff

Вміти знімати коментарі з файлу так важливо ... Який хороший спосіб це зробити?


1
ви не можете видалити частини рядка греппом. ви можете використовувати sed для цього
чудо173

2
Ваш текст та ваш приклад суперечать. Ви пишете про коментовані рядки, але чітко з останнього рядка ви маєте на увазі частини рядка. І тоді перший рядок із коментарем видаляється, включаючи EOL, а другий може бути, але не ясно, як це останній рядок. Будь ласка, перефразовуйте "коментовані рядки", щоб бути точними та розмежувати ваші приклади.
Антон

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

2
Як би echo '#' # output a #оброблялася лінія ?
Kusalananda

3
@Questionmark Я можу бути розумним, але я не пишу-розумний грамат-аналізатор розумний.
Kusalananda

Відповіді:


40

Один із способів видалити всі коментарі - це використання grepз -oопцією:

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

де

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

Зауважте, що порожні рядки також буде видалено, але рядки з лише пробілами залишаться.


2
Я б скориставсяgrep -v '^#' file > newfilewithoutcomments
Базиле Старинкевич

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

Цей варіант для мене краще працює (на Mac):grep -o '^[^#].*' file
П’єрз

Зауважень немає, але я бачу на своєму місці купу білого простору? sedрішення має лише один порожній рядок, здається, твердий аргумент для використання іншої відповіді, якщо я щось не пропускаю?
JBallin

@JBallin Ви визначили певний псевдонім, grepможливо? Спробуйте перейти grepна command grep, якщо ви все ще бачите пробіли, розміщуючи зразок введення.
jimmij

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-й рядок замінено на новий рядок у цьому випадку.
αғsnιη

1
Спробуйте це зі сценарієм, що містить цю sedкоманду ...
Kusalananda

З цим не вийде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прикладу ОП.
Джозеф Р.

@JosephR. хороший улов. Я пропустив це раніше. У цьому випадку grep -o '^[^#]*' fileбуло б найкращим рішенням. це вже пояснюється jimmij. дякую за Ваш відгук
Раза

З цим не вийдеprint "#tag" # Print a hashtag.
Рей Баттерворт,

2

Мені подобається відповідь Йозефа, але вона потрібна, щоб знімати // коментарі, тому я трохи змінив її і перевірив на redhat

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

# example
cat SomeFile | nocom | less

Б'юсь об заклад, що є кращий спосіб видалити порожні рядки, ніж використання рядків, але це було швидким і брудним рішенням, яке я використовував.

-черки


З цим не вийдеprint "#tag" # Print a hashtag.
Рей Баттерворт,


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

Він використовується #як роздільник стовпців і зберігає лише перший стовпець (тобто все, що раніше #).


1
Якщо YOUR_FILEце скрипт, що містить ці команди, то сценарій залишиться cat YOUR_FILE | cut -'у файлі у цьому рядку.
Kusalananda

1

Використовуйте вирази, як

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

: -v: зробить зворотну відповідність

: #: відповідатиме всім рядкам, починаючи з #

: $ ^: відповідатиме усім порожнім рядкам


1
Ні, #заповіт буде відповідати будь-де на лінії та видалить усю лінію.
ilkkachu

1

Найкращим рішенням буде використання команди:

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

The -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, тому не думав про це. Я думаю, його потрібно було б адаптувати для пошуку та видалення будь-яких коментарів, які лежать у тій же лінії, що і код. Я щойно побачив краще рішення мого конкретного питання вище: egrep -v "# | $ ^"
jackbmg
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.