Bagaimana saya bisa menghapus semua komentar dari file?

21

Saya punya file dengan komentar:

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

Saya hanya ingin mencetak semua kode tanpa komentar:

foo
bar
stuff
morestuff
evenmorestuff

Mampu menghapus komentar dari file sangat penting ... Apa cara yang baik untuk melakukannya?

Tanda tanya
sumber
1
Anda tidak dapat menghapus bagian dari garis dengan grep. Anda dapat menggunakan sed untuk ini
miracle173
2
Teks Anda dan contoh Anda bertentangan. Anda menulis tentang baris yang dikomentari, tetapi jelas dari baris terakhir yang Anda maksud adalah bagian baris. Dan kemudian baris pertama dengan komentar dihapus termasuk EOL, dan yang kedua mungkin, tetapi tidak jelas karena itu adalah baris terakhir. Harap ulang kata-kata 'baris yang dikomentari' menjadi tepat dan ambigukan contoh Anda.
Anthon
5
coba gunakan awk -F\# '$1!="" { print $1 ;} '.
Archemar
2
Bagaimana garis seperti echo '#' # output a #akan ditangani?
Kusalananda
3
@Questionmark Saya mungkin pintar, tapi saya tidak menulis pintar shell-tata bahasa-parser.
Kusalananda

Jawaban:

40

Salah satu cara untuk menghapus semua komentar adalah dengan menggunakan grepdengan -opilihan:

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

dimana

  • -o: cetakan hanya cocok dengan bagian dari garis
  • pertama ^: awal baris
  • [^#]*: karakter apa pun kecuali yang #berulang nol atau lebih

Perhatikan bahwa garis kosong juga akan dihapus, tetapi garis dengan hanya spasi akan tetap ada.

jimmij
sumber
2
Saya akan menggunakangrep -v '^#' file > newfilewithoutcomments
Basile Starynkevitch
1
Perlu dicatat ini BUKAN metode umum untuk skrip shell, seperti misalnya baris somvar='I am a long complicated string ## with special characters' # and I am a commenttidak akan ditangani dengan benar.
Wildcard
Varian ini berfungsi lebih baik untuk saya (di Mac):grep -o '^[^#].*' file
Pierz
Komentar sudah hilang tapi saya melihat banyak ruang putih di tempat mereka di output? sedsolusi hanya memiliki satu baris kosong, sepertinya argumen yang kuat untuk menggunakan jawaban lain, kecuali saya kehilangan sesuatu?
JBallin
@ Jonallin Apakah Anda mendefinisikan beberapa alias untuk grepmungkin? Coba ubah grepke command grep, jika Anda masih melihat spasi memposting input sampel.
jimmij
31

aku percaya sed bisa melakukan pekerjaan yang jauh lebih baik daripada ini grep. Sesuatu seperti ini:

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

Penjelasan

  • sedsecara default akan melihat file Anda baris demi baris dan mencetak setiap baris setelah mungkin menerapkan transformasi dalam tanda kutip. ( sed '' your_filehanya akan mencetak semua baris tidak berubah).
  • Di sini kita memberi sed dua perintah untuk tampil di setiap baris (dipisahkan dengan tanda titik koma).
  • Perintah pertama mengatakan: /^[[:blank:]]*#/d . Dalam bahasa Inggris, itu berarti jika baris cocok dengan hash pada awalnya (didahului dengan jumlah kosong awal), hapus baris itu (tidak akan dicetak).
  • Perintah kedua adalah: s/#.*// . Dalam bahasa Inggris, gantilah tanda hash diikuti oleh banyak hal yang dapat Anda temukan (sampai akhir baris) yaitu tanpa apa-apa (tidak ada ruang kosong di antara dua yang terakhir //).
  • Ringkasnya, ini akan dijalankan melalui file Anda menghapus baris yang seluruhnya terdiri dari komentar dan setiap baris yang tersisa setelah itu akan memiliki komentar dicoret dari mereka.
Joseph R.
sumber
1
Ini juga akan menghapus apa pun yang ditemukan setelah hash di dalam string , bukan? Misalnya mystring="Hello I am a #hash" akan menjadi mystring="Hello I am a"
javadba
@javadba, ya, tapi pada saat itu Anda sebaiknya menggunakan parser penuh. Apa yang akan menggunakan data ini yang dapat memahami penawaran dan penugasan variabel tetapi tidak dapat menangani komentar? (Inilah sebabnya mengapa banyak file konfigurasi seperti crontabhanya memungkinkan komentar baris penuh, dengan atau tanpa spasi kosong, tapi jangan izinkan komentar tertinggal di baris. Logikanya JAUH lebih sederhana. Gunakan hanya yang pertama dari dua instruksi Sed dalam jawaban ini untuk stripper komentar crontab.)
Wildcard
jawaban yang bagus, ini tampak seperti keseimbangan yang baik antara utilitas vs kompleksitas untuk beragam kasus penggunaan umum, tetapi dalam kasus yang Anda tahu sebelumnya bahwa Anda hanya perlu menghapus baris yang dimulai langsung dengan #(pada kolom 1), apakah ada manfaat untuk sedlebih grep -v "^#"?
RBF06
4

Anda dapat mencapai output yang dibutuhkan menggunakan perintah sed. Perintah di bawah ini telah melakukan trik untukku.

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

Dimana

  • #.*$- Regexp akan memfilter semua string yang dimulai dengan #hingga akhir baris

Di sini kita perlu menghapus garis-garis itu sehingga kita diganti dengan bagian 'penggantian' kosong jadi lewati.

  • g - Menyebutkan pencarian berulang pola hingga akhir file tercapai.

Sintaks umum sed: s/regexp/replacement/flags FileName

Sridhar DD
sumber
2
Catatan: Baris ke-4 diganti dengan baris baru dalam hal ini.
αғsнιη
1
Cobalah dengan skrip yang berisi sedperintah itu ...
Kusalananda
Itu tidak akan menanganiprint "#tag" # Print a hashtag.
Ray Butterworth
3

Seperti yang telah ditunjukkan orang lain, sed dan alat berbasis teks lainnya tidak akan berfungsi dengan baik jika ada bagian skrip yang terlihat seperti komentar tetapi sebenarnya tidak. Misalnya, Anda dapat menemukan # di dalam string, atau yang agak umum $#dan ${#param}.

Saya menulis formatter shell bernama shfmt , yang memiliki fitur untuk memperkecil kode. Itu termasuk menghapus komentar, antara lain:

$ 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 dan printer adalah paket Go, jadi jika Anda menginginkan solusi khusus, seharusnya cukup mudah untuk menulis program Go 20-line untuk menghapus komentar dengan cara yang Anda inginkan.

Daniel
sumber
2

Anda dapat menggunakan pertandingan terbalik seperti ini:

    #grep -v "#" filename

-v, --invert-match Balikkan indra pencocokan, untuk memilih jalur yang tidak cocok. (-v ditentukan oleh POSIX.)

Raza
sumber
2
@alinh Terima kasih telah meninjau jawabannya. Harap perhatikan bahwa pertanyaan tidak hanya diperlukan pada awal baris tetapi di mana pun dalam file. Ini juga ditunjukkan dalam hasil yang diharapkan dalam pertanyaan di atas. Jawaban saya akan salah jika saya hanya mencari awal baris.
Raza
zzz.
salahku
1
Ini sepenuhnya akan menghapus baris yang dimulai dengan evenmorestuffdalam contoh OP.
Joseph R.
@ JosephephR. tangkapan yang bagus. Saya melewatkan itu sebelumnya. Dalam hal ini grep -o '^[^#]*' fileakan menjadi solusi terbaik. ini sudah dijelaskan oleh jimmij. terima kasih atas ulasan Anda
Raza
Itu tidak akan menanganiprint "#tag" # Print a hashtag.
Ray Butterworth
2

Saya suka jawaban joseph tetapi membutuhkannya untuk menghapus // komentar juga jadi saya memodifikasinya sedikit & diuji pada redhat

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

# example
cat SomeFile | nocom | less

Saya yakin ada cara yang lebih baik untuk menghapus garis kosong daripada menggunakan string tetapi itu adalah solusi cepat & kotor yang saya gunakan.

-tepuk tangan

brandon
sumber
Itu tidak akan menanganiprint "#tag" # Print a hashtag.
Ray Butterworth
2

Ini berhasil untuk saya

sed -i.old -E  "/^(#.*)$/d" file 
David Okwii
sumber
Itu tidak akan menanganiprint "#tag" # Print a hashtag.
Ray Butterworth
1
cat YOUR_FILE | cut -d'#' -f1

Ini digunakan #sebagai pemisah kolom dan membuat hanya kolom pertama (itu adalah segalanya sebelumnya #).

Alexey
sumber
1
Jika YOUR_FILEskrip berisi perintah-perintah itu, skrip akan meninggalkan cat YOUR_FILE | cut -'dalam file pada baris itu.
Kusalananda
1

Gunakan ekspresi seperti

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

: -v: akan melakukan kecocokan terbalik

: #: akan cocok dengan semua baris yang dimulai dengan #

: $ ^: akan cocok dengan semua baris kosong

aditya
sumber
1
Tidak, #akan cocok di mana saja di telepon, dan menghapus seluruh telepon.
ilkkachu
1

Solusi terbaik adalah dengan menggunakan perintah:

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

-I adalah sunting di tempat tetapi awalan langsung berikut memberitahu sed untuk membuat cadangan. Dalam hal ini dengan ekstensi tanggal (ntp.conf.date) Kami menjalankan dua perintah masing-masing dengan ruang alamat, yang pertama menghapus baris-baris yang dikomentari dan yang kedua, dipisahkan dari yang pertama dengan titik koma, menghapus baris yang kosong.

Saya menemukan solusi ini di: theurbanpenguin.com

yyoti
sumber
0

Tak satu pun dari jawaban lain yang tampaknya melakukan keadilan ini, mereka pergi di baris kosong, atau di baris di mana komentar tidak pada karakter pertama. Saya akhirnya menggunakan ini:

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

Ini mengatur alias, sehingga Anda tidak harus menghafalnya (yang tidak mungkin dimulai dengan). Buka sesi baru, dan Anda akan memiliki nocomperintah baru . Maka Anda bisa saja

nocom /etc/foobar.conf

Tepuk tangan.

bviktor
sumber
1
tidak ada gunanya mencocokkan .*$di regex pertama - jangkar tidak berguna dan Anda tidak menangkap teks yang cocok untuk digunakan dalam pengganti. gunakan saja^\s*
Jeff Schaller
Itu tidak akan menanganiprint "#tag" # Print a hashtag.
Ray Butterworth
0

Mengikuti jawaban ke-2 dari Joseph R., saya menambahkan /^$/duntuk menghapus baris kosong.

sed '/^[[:blank:]]*#/d;s/#.*//;/^$/d'
Pierre-Damien
sumber
-1

Saya memposting apa yang cocok untuk saya dan sepertinya paling masuk akal, setelah membaca yang lain, dengan penjelasan. Beberapa posting hampir selesai, tetapi saya belum bisa berkomentar (karena saya seorang pemula):

grep -E -v "(^#.*|^$)" filename
  • -E = menginterpretasikan pola berikut sebagai ekspresi reguler, mirip dengan menggunakan egrep
  • -v = cetak inversi dari pola (garis yang tidak cocok dengan ekspresi akan dicetak)
  • "(^#.*|^$)"= ini memiliki pipa yang menunjukkan pernyataan ATAU. Ungkapan ini mengatakan untuk mencetak baris yang dimulai dengan #(dan apa pun setelahnya) ATAU baris apa pun dengan nol karakter antara awal dan akhir baris.

The -vakan mencetak pada layar inversi itu, yang akan ada sejalan dengan karakter yang tidak dimulai dengan #.

jackbmg
sumber
Itu tidak akan menanganiprint "#tag" # Print a hashtag.
Ray Butterworth
Ah, benar ... tentu saja. Terima kasih telah menunjukkannya. Saya sedang mencari jawaban sehubungan dengan file konfigurasi linux biasa, seperti konfigurasi pam.d, jadi saya tidak memikirkan itu. Saya kira itu harus disesuaikan untuk menemukan dan menghapus komentar yang ada pada baris yang sama dengan kode. Saya hanya melihat mungkin solusi yang lebih baik untuk masalah khusus saya di atas: egrep -v "# | $ ^"
jackbmg