Jak mogę usunąć wszystkie komentarze z pliku?


21

Mam plik z komentarzami:

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

Chcę tylko wydrukować cały niekomentowany kod:

foo
bar
stuff
morestuff
evenmorestuff

Możliwość usuwania komentarzy z pliku jest bardzo ważna ... Jak to zrobić?


1
nie można usunąć części linii za pomocą grep. możesz do tego użyć sed
— miracle173

2
Twój tekst i przykład są sprzeczne. Piszesz o liniach komentowanych, ale wyraźnie od ostatniego wiersza masz na myśli części linii. Następnie usuwany jest pierwszy wiersz z komentarzem, w tym EOL, i może być druga sekunda, ale nie jest to jasne, ponieważ jest to ostatni wiersz. Przeformułuj „wiersze skomentowane”, aby były dokładne i jednoznaczne w swoich przykładach.
— Anthon

5
spróbuj użyć awk -F\# '$1!="" { print $1 ;} '.
— Archemar

2
Jak echo '#' # output a #obsłużyć linię ?
— Kusalananda

3
@Questionmark Mogę być sprytny, ale nie piszę sprytnego parsera gramatyki.
— Kusalananda

Odpowiedzi:


40

Jednym ze sposobów, aby usunąć wszystkie komentarze jest skorzystanie grepz -oopcji:

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

gdzie

  • -o: drukuje tylko dopasowaną część linii
  • pierwszy ^: początek linii
  • [^#]*: dowolny znak z wyjątkiem #powtarzanego zera lub więcej razy

Zauważ, że puste linie również zostaną usunięte, ale pozostaną tylko linie ze spacjami.


2
Chciałbym użyćgrep -v '^#' file > newfilewithoutcomments
— Basile Starynkevitch

1
Należy zauważyć, że NIE jest to ogólna metoda dla skryptów powłoki, ponieważ na przykład linia somvar='I am a long complicated string ## with special characters' # and I am a commentnie będzie obsługiwana poprawnie.
— Wildcard,

Ten wariant działa dla mnie lepiej (na komputerze Mac):grep -o '^[^#].*' file
— Pierz

Komentarze zniknęły, ale na wydruku widzę kilka białych spacji? sedrozwiązanie ma tylko jedną pustą linię, wydaje się solidnym argumentem, aby użyć innej odpowiedzi, chyba że czegoś brakuje?
— JBallin

@JBallin Czy może zdefiniowałeś jakiś alias grep? Spróbuj zmienić grepna command grep, jeśli nadal widzisz spacje po przykładowym danych wejściowych.
— jimmij

31

Wierzę, że sedmożna to zrobić znacznie lepiej niż grep. Coś takiego:

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

Wyjaśnienie

  • seddomyślnie spojrzy na plik linia po linii i wydrukuje każdą linię po ewentualnym zastosowaniu transformacji w cudzysłowie ( sed '' your_filepo prostu wydrukuje wszystkie linie bez zmian).
  • Tutaj podajemy seddwa polecenia do wykonania w każdej linii (są one oddzielone średnikiem).
  • Pierwsze polecenie mówi: /^[[:blank:]]*#/d. W języku angielskim oznacza to, że jeśli wiersz pasuje do skrótu na początku (poprzedzony dowolną liczbą wiodących odstępów), usuń ten wiersz (nie zostanie wydrukowany).
  • Drugie polecenie brzmi: s/#.*//. W języku angielskim, zamień znak krzyżyka, po którym następuje tyle rzeczy, ile możesz (to znaczy do końca linii) na nic (nic nie jest pustą przestrzenią między dwoma ostatnimi //).
  • Podsumowując, spowoduje to przejście przez linie usuwania plików, które składają się wyłącznie z komentarzy, a wszelkie pozostałe linie po nich spowodują usunięcie z nich komentarzy.

1
Usunie również wszystko, co zostanie znalezione po haszu wewnątrz ciągu , prawda? Np. mystring="Hello I am a #hash" Stanie się mystring="Hello I am a"
— javadba,

@javadba, tak, ale w tym momencie równie dobrze możesz użyć pełnego parsera. Co będzie wykorzystywało te dane, które mogą zrozumieć cytaty i przypisania zmiennych, ale nie mogą obsługiwać komentarzy? (Z tego powodu wiele plików konfiguracyjnych, takich jak crontabtylko dopuszcza komentarze pełnowymiarowe, z wiodącymi białymi znakami lub bez nich, ale nie zezwala na końcowe komentarze w linii. Logika jest DUŻO prostsza. Użyj tylko pierwszej z dwóch instrukcji Sed w tej odpowiedzi do ściągnięcia komentarza do pliku crontab.)
— Wildcard,

świetna odpowiedź, wygląda to na doskonałą równowagę użyteczności i złożoności dla szerokiej gamy ogólnych przypadków użycia, ale w przypadku, gdy wiesz z góry, że musisz tylko usunąć linie zaczynające się bezpośrednio #(w kolumnie 1), jest jakaś korzyść dla sedprzejęcia grep -v "^#"?
— RBF06

4

Wymaganą moc wyjściową można osiągnąć za pomocą polecenia sed. Poniższe polecenie załatwiło sprawę.

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

Gdzie

  • #.*$- Regexp przefiltruje wszystkie ciągi, które zaczynają #się od końca linii

Tutaj musimy usunąć te wiersze, więc zastąpiliśmy pustą, więc pomijam część „zamienną”.

  • g - wzmianka o powtarzanym wyszukiwaniu wzoru aż do osiągnięcia końca pliku.

Ogólna składnia sed: s/regexp/replacement/flags FileName


2
Uwaga: w tym przypadku 4. linia zastąpiona nową linią.
— αғsнιη

1
Spróbuj tego ze skryptem zawierającym to sedpolecenie ...
— Kusalananda

Nie poradzi sobieprint "#tag" # Print a hashtag.
— Ray Butterworth

3

Jak zauważyli inni, sed i inne narzędzia tekstowe nie będą działały dobrze, jeśli jakakolwiek część skryptu wygląda jak komentarz, ale tak naprawdę nie jest. Na przykład możesz znaleźć # w ciągu lub raczej wspólne $#i ${#param}.

Napisałem program do formatowania powłok o nazwie shfmt , który ma funkcję zmniejszania kodu. Obejmuje to usuwanie komentarzy, między innymi:

$ 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'

Parser i drukarka są pakietami Go, więc jeśli potrzebujesz niestandardowego rozwiązania, napisanie 20-liniowego programu Go w celu usunięcia komentarzy w dokładnie taki sposób, jak chcesz, powinno być dość łatwe.


2

Możesz użyć dopasowania odwróconego w następujący sposób:

    #grep -v "#" filename

-v, --invert-match Odwraca sens dopasowania, aby wybrać niepasujące linie. (-v jest określone przez POSIX).


2
@alinh Dziękujemy za zapoznanie się z odpowiedzią. Pamiętaj, że pytanie wymagało nie tylko początku wiersza, ale dowolnego miejsca w pliku. Pokazuje to również jego oczekiwany wynik w powyższym pytaniu. Moja odpowiedź byłaby niepoprawna, gdybym tylko szukał początku linii.
— Raza

zzz. mój zły, nie widziałem ostatniego wiersza :(
— alinh

1
Spowoduje to całkowite usunięcie linii zaczynającej się evenmorestuffna przykładzie PO.
— Joseph R.

@JosephR. dobry chwyt. Tęskniłem wcześniej. W takim przypadku grep -o '^[^#]*' filebyłoby najlepszym rozwiązaniem. tłumaczy to jimmij. dzięki za recenzję
— Raza,

Nie poradzi sobieprint "#tag" # Print a hashtag.
— Ray Butterworth

2

Podoba mi się odpowiedź Josepha, ale potrzebowałem jej również do usunięcia // komentarzy, więc nieco ją zmodyfikowałem i przetestowałem na redhat

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

# example
cat SomeFile | nocom | less

Założę się, że jest lepszy sposób na usunięcie pustych linii niż używanie ciągów, ale to było szybkie i brudne rozwiązanie, którego użyłem.

-Twoje zdrowie


Nie poradzi sobieprint "#tag" # Print a hashtag.
— Ray Butterworth


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

Służy #jako separator kolumn i zachowuje tylko pierwszą kolumnę (czyli wszystko wcześniej #).


1
Jeśli YOUR_FILEskrypt zawiera te polecenia, skrypt pozostawiłby się cat YOUR_FILE | cut -'w pliku w tym wierszu.
— Kusalananda

1

Użyj wyrażenia jak

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

: -v: wykona odwrócenie dopasowania

: #: dopasuje wszystkie linie zaczynające się od #

: $ ^: dopasuje wszystkie puste linie


1
Nie, #dopasuje się w dowolnym miejscu linii i usunie całą linię.
— ilkkachu

1

Najlepszym rozwiązaniem byłoby użycie polecenia:

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

-I jest edycją lokalną, ale przedrostek bezpośrednio po nim mówi sedowi, aby utworzył kopię zapasową. W tym przypadku z rozszerzeniem daty (ntp.conf.date) Wykonujemy dwa polecenia, każde z przestrzenią adresową, pierwsze usuwa skomentowane linie, a drugie, oddzielone od pierwszego średnikiem, usuwa puste wiersze.

Znalazłem to rozwiązanie na: theurbanpenguin.com


0

Żadna z pozostałych odpowiedzi wydaje się nie oddawać tej sprawiedliwości, albo zostawiają w pustych liniach, albo w liniach, w których komentarz nie jest na pierwszym znaku. Skończyło się na tym:

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

Spowoduje to skonfigurowanie aliasu, abyś nie musiał go zapamiętywać (co jest niemożliwe na początku). Otwórz nową sesję, a będziesz mieć nowe nocompolecenie. Więc możesz po prostu

nocom /etc/foobar.conf

Twoje zdrowie.


1
dopasowanie .*$pierwszego wyrażenia regularnego nie ma większego sensu - kotwica nie jest przydatna i nie przechwytujesz dopasowanego tekstu do użycia w zamianie. użyj tylko^\s*
— Jeff Schaller

Nie poradzi sobieprint "#tag" # Print a hashtag.
— Ray Butterworth

0

Po drugiej odpowiedzi Josepha R. dodaję, /^$/daby usunąć pusty wiersz.

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

-1

Publikuję to, co działa dla mnie i wydaje się mieć sens, po przeczytaniu innych, z wyjaśnieniem. Kilka postów było blisko, ale nie mogłem jeszcze komentować (ponieważ jestem nowicjuszem):

grep -E -v "(^#.*|^$)" filename
  • -E = interpretuj następujący wzorzec jako wyrażenie regularne, podobne do używania egrep
  • -v = wydrukuj odwrócenie wzoru (zostaną wydrukowane wiersze, które nie pasują do wyrażenia)
  • "(^#.*|^$)"= to ma potok oznaczający instrukcję OR. To wyrażenie mówi, aby wypisać dowolny wiersz rozpoczynający się od #(i cokolwiek innego po nim) LUB dowolny wiersz z zerowymi znakami między początkiem i końcem wiersza.

-vWypisze na ekranie odwrócenie tego, co będzie jakaś linia z postaciami, które nie rozpocznie się z #.


Nie poradzi sobieprint "#tag" # Print a hashtag.
— Ray Butterworth

Ach, racja ... oczywiście. Dzięki za zwrócenie na to uwagi. Szukałem odpowiedzi dotyczącej typowych plików konfiguracyjnych Linux, takich jak konfiguracje pam.d, więc o tym nie pomyślałem. Myślę, że trzeba by go dostosować, aby znaleźć i usunąć wszelkie komentarze, które leżą w tym samym wierszu co kod. Właśnie widziałem prawdopodobnie lepsze rozwiązanie mojego konkretnego problemu powyżej: egrep -v "# | $ ^"
— jackbmg
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.