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ć?

Znak zapytania
źródło
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.

jimmij
źródło
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.
Joseph R.
źródło
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

Sridhar DD
źródło
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.

Daniel
źródło
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).

Raza
źródło
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

brandon
źródło
Nie poradzi sobieprint "#tag" # Print a hashtag.
Ray Butterworth
2

To zadziałało dla mnie

sed -i.old -E  "/^(#.*)$/d" file 
David Okwii
źródło
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 #).

Alexey
źródło
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

aditya
źródło
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

jyoti
źródło
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.

Bviktor
źródło
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'
Pierre-Damien
źródło
-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 #.

jackbmg
źródło
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