Làm thế nào tôi có thể xóa tất cả các ý kiến ​​từ một tập tin?


21

Tôi có một tập tin với ý kiến:

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

Tôi chỉ muốn in tất cả các mã chưa hoàn thành:

foo
bar
stuff
morestuff
evenmorestuff

Có thể loại bỏ các bình luận ra khỏi một tập tin là rất quan trọng ... Cách tốt để làm điều đó là gì?


1
bạn không thể loại bỏ các phần của một dòng bằng grep. bạn có thể sử dụng sed cho việc này
miracle173

2
Văn bản của bạn và ví dụ của bạn mâu thuẫn. Bạn viết về các dòng được nhận xét, nhưng rõ ràng từ dòng cuối cùng bạn có nghĩa là các phần dòng. Và sau đó, dòng đầu tiên với một nhận xét sẽ bị xóa bao gồm EOL, và dòng thứ hai có thể, nhưng không rõ ràng vì đó là dòng cuối cùng. Vui lòng viết lại 'dòng nhận xét' để chính xác và phân biệt các ví dụ của bạn.
Anthon

5
thử sử dụng awk -F\# '$1!="" { print $1 ;} '.
Archemar

2
Làm thế nào một dòng như echo '#' # output a #sẽ được xử lý?
Kusalananda

3
@Questionmark Tôi có thể thông minh, nhưng tôi không viết trình phân tích cú pháp ngữ pháp thông minh.
Kusalananda

Câu trả lời:


40

Một cách để loại bỏ tất cả các ý kiến ​​là sử dụng grepvới -otùy chọn:

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

Ở đâu

  • -o: chỉ in một phần của dòng
  • đầu tiên ^: bắt đầu của dòng
  • [^#]*: bất kỳ ký tự nào ngoại trừ #lặp lại 0 lần trở lên

Lưu ý rằng các dòng trống cũng sẽ bị xóa, nhưng các dòng chỉ có khoảng trắng sẽ ở lại.


2
Tôi sẽ sử dụnggrep -v '^#' file > newfilewithoutcomments
Basile Starynkevitch

1
Cần lưu ý đây KHÔNG phải là một phương pháp chung cho các kịch bản shell, ví dụ như dòng somvar='I am a long complicated string ## with special characters' # and I am a commentsẽ không được xử lý chính xác.
tự đại diện

Biến thể này hoạt động tốt hơn đối với tôi (trên máy Mac):grep -o '^[^#].*' file
Pierz

Các ý kiến ​​đã biến mất nhưng tôi thấy một loạt các khoảng trắng ở vị trí của chúng trong đầu ra? sedgiải pháp chỉ có một dòng trống, có vẻ như là một đối số chắc chắn để sử dụng câu trả lời khác, trừ khi tôi thiếu một cái gì đó?
JBallin

@JBallin Bạn có định nghĩa một số bí danh cho grepcó thể không? Hãy thử thay đổi grepthành command grep, nếu bạn vẫn thấy khoảng trắng đăng đầu vào mẫu.
jimmij

31

Tôi tin rằng sedcó thể làm một công việc này tốt hơn nhiều grep. Một cái gì đó như thế này:

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

Giải trình

  • sedtheo mặc định sẽ xem xét từng dòng tệp của bạn và in từng dòng sau khi có thể áp dụng các biến đổi trong dấu ngoặc kép. ( sed '' your_filesẽ chỉ in tất cả các dòng không thay đổi).
  • Ở đây chúng tôi đưa ra sedhai lệnh để thực hiện trên mỗi dòng (chúng được phân tách bằng dấu chấm phẩy).
  • Lệnh đầu tiên nói : /^[[:blank:]]*#/d. Trong tiếng Anh, điều đó có nghĩa là nếu dòng này khớp với hàm băm ở đầu (trước bất kỳ số lượng khoảng trống hàng đầu nào), hãy xóa dòng đó (nó sẽ không được in).
  • Lệnh thứ hai là : s/#.*//. Trong tiếng Anh có nghĩa là, thay thế một dấu băm theo sau là nhiều thứ bạn có thể tìm thấy (cho đến cuối dòng, nghĩa là) bằng không có gì (không có gì là khoảng trống giữa hai cuối cùng //).
  • Tóm lại, điều này sẽ chạy qua tập tin của bạn xóa các dòng hoàn toàn bao gồm các bình luận và bất kỳ dòng nào còn lại sau đó sẽ có các bình luận bị loại ra khỏi chúng.

1
Nó cũng sẽ xóa bất cứ thứ gì tìm thấy sau khi băm bên trong một chuỗi , phải không? Ví dụ: mystring="Hello I am a #hash" sẽ trở thành mystring="Hello I am a"
javadba

@javadba, vâng, nhưng tại thời điểm đó, bạn cũng có thể sử dụng một trình phân tích cú pháp đầy đủ. Điều gì sẽ được sử dụng dữ liệu này có thể hiểu các trích dẫn và bài tập biến nhưng không thể xử lý các bình luận? (Đây là lý do tại sao nhiều tệp cấu hình như crontabchỉ cho phép nhận xét toàn dòng, có hoặc không có khoảng trắng hàng đầu, nhưng không cho phép nhận xét theo dõi trên một dòng. Logic đơn giản hơn. Chỉ sử dụng đầu tiên trong hai lệnh Sed trong câu trả lời này cho một vũ nữ thoát y bình luận crontab.)
Wildcard

câu trả lời tuyệt vời, điều này có vẻ như là một sự cân bằng tuyệt vời của tiện ích và sự phức tạp cho một loạt các trường hợp sử dụng chung, nhưng trong trường hợp bạn biết trước rằng bạn chỉ cần xóa các dòng bắt đầu trực tiếp với #(trong cột 1), Có lợi ích gì sedhơn grep -v "^#"không?
RBF06

4

Bạn có thể đạt được đầu ra cần thiết bằng cách sử dụng lệnh sed. Lệnh dưới đây đã thực hiện các mẹo cho tôi.

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

Ở đâu

  • #.*$- Regapi sẽ lọc tất cả các chuỗi bắt đầu từ đầu #đến cuối dòng

Ở đây chúng ta cần loại bỏ những dòng đó để chúng ta thay thế bằng phần trống để bỏ qua phần 'thay thế'.

  • g - đề cập đến việc tìm kiếm lặp đi lặp lại của mẫu cho đến khi kết thúc tập tin.

Cú pháp chung của sed: s/regexp/replacement/flags FileName


2
lưu ý: dòng thứ 4 thay thế bằng dòng mới trong trường hợp này.
αғsнιη

1
Hãy thử điều đó với một tập lệnh chứa sedlệnh đó ...
Kusalananda

Nó sẽ không xử lýprint "#tag" # Print a hashtag.
Ray Butterworth

3

Như những người khác đã chỉ ra, sed và các công cụ dựa trên văn bản khác sẽ không hoạt động tốt nếu bất kỳ phần nào của tập lệnh trông giống như các nhận xét nhưng thực tế thì không. Ví dụ: bạn có thể tìm thấy một # bên trong một chuỗi, hoặc khá phổ biến $#${#param}.

Tôi đã viết một trình định dạng shell gọi là shfmt , có một tính năng để thu nhỏ mã. Điều đó bao gồm xóa bình luận, trong số những thứ khác:

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

Trình phân tích cú pháp và máy in là các gói Go, vì vậy nếu bạn muốn một giải pháp tùy chỉnh, việc viết chương trình Go 20 dòng để xóa bình luận theo cách chính xác mà bạn muốn khá dễ dàng.


2

Bạn có thể sử dụng đảo ngược như thế này:

    #grep -v "#" filename

-v, --invert-match Đảo ngược ý nghĩa khớp, để chọn các dòng không khớp. (-v được chỉ định bởi POSIX.)


2
@alinh Cảm ơn đã xem lại câu trả lời. Xin lưu ý rằng câu hỏi yêu cầu không chỉ ở đầu dòng mà bất kỳ nơi nào trong tệp. Điều này cũng cho thấy kết quả mong đợi của anh ấy / cô ấy trong câu hỏi trên. Câu trả lời của tôi sẽ không chính xác nếu tôi chỉ tìm kiếm đầu dòng.
Raza

zzz. xấu của tôi, đã không nhìn thấy dòng cuối cùng :(
alinh

1
Điều này sẽ loại bỏ hoàn toàn dòng bắt đầu bằng evenmorestuffví dụ của OP.
Joseph R.

@JosephR. nắm bắt tốt. Tôi đã bỏ lỡ điều đó sớm hơn. Trong trường hợp này grep -o '^[^#]*' filesẽ là giải pháp tốt nhất. điều này đã được giải thích bởi jimmij. cảm ơn bạn đã đánh giá
Raza

Nó sẽ không xử lýprint "#tag" # Print a hashtag.
Ray Butterworth

2

Tôi thích câu trả lời của joseph nhưng cũng cần nó để loại bỏ // bình luận vì vậy tôi đã sửa đổi nó một chút và thử nghiệm trên redhat

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

# example
cat SomeFile | nocom | less

Tôi cá là có một cách tốt hơn để loại bỏ các dòng trống hơn là sử dụng các chuỗi nhưng đó là giải pháp nhanh và bẩn mà tôi đã sử dụng.

-nhà


Nó sẽ không xử lýprint "#tag" # Print a hashtag.
Ray Butterworth


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

Nó sử dụng #như dấu tách cột và chỉ giữ cột đầu tiên (đó là tất cả mọi thứ trước đó #).


1
Nếu YOUR_FILElà một tập lệnh chứa các lệnh đó, tập lệnh sẽ để lại cat YOUR_FILE | cut -'trong tập tin trên dòng đó.
Kusalananda

1

Sử dụng biểu thức như

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

: -v: sẽ thực hiện đảo ngược

: #: sẽ khớp với tất cả các dòng bắt đầu bằng #

: $ ^: sẽ khớp với tất cả các dòng trống


1
Không, #sẽ khớp bất cứ nơi nào trên dòng và loại bỏ toàn bộ dòng.
ilkkachu

1

Giải pháp tốt nhất là sử dụng lệnh:

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

-I là chỉnh sửa tại chỗ nhưng tiền tố trực tiếp nói với sed để tạo bản sao lưu. Trong trường hợp này có phần mở rộng ngày (ntp.conf.date) Chúng tôi chạy hai lệnh mỗi lệnh có một không gian địa chỉ, đầu tiên xóa các dòng nhận xét và thứ hai, được phân tách từ đầu tiên bằng dấu chấm phẩy, xóa các dòng trống.

Tôi tìm thấy giải pháp này trên: theurbanpenguin.com


0

Không có câu trả lời nào khác có vẻ như thực hiện công lý này, chúng hoặc để lại trong các dòng trống hoặc để lại trong các dòng mà nhận xét không ở ký tự đầu tiên. Tôi đã kết thúc bằng cách sử dụng này:

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

Điều này thiết lập một bí danh, để bạn không phải ghi nhớ nó (điều này là không thể bắt đầu). Mở một phiên mới và bạn sẽ có nocomlệnh mới . Sau đó, bạn có thể chỉ

nocom /etc/foobar.conf

Chúc mừng.


1
không có nhiều điểm phù hợp .*$trong regex đầu tiên - neo không hữu ích và bạn không nắm bắt văn bản phù hợp để sử dụng thay thế. chỉ sử dụng^\s*
Jeff Schaller

Nó sẽ không xử lýprint "#tag" # Print a hashtag.
Ray Butterworth

0

Theo câu trả lời thứ 2 của Joseph R., tôi thêm /^$/dvào để xóa dòng trống.

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

-1

Tôi đang đăng những gì làm việc cho tôi và dường như có ý nghĩa nhất, sau khi đọc qua những người khác, với lời giải thích. Một vài bài viết đã đến gần, nhưng tôi chưa thể bình luận (vì tôi là người mới):

grep -E -v "(^#.*|^$)" filename
  • -E = diễn giải mẫu sau dưới dạng biểu thức chính quy, tương tự như sử dụng egrep
  • -v = in đảo ngược của mẫu (các dòng không khớp với biểu thức sẽ được in)
  • "(^#.*|^$)"= cái này có một đường ống chỉ định một câu lệnh OR. Biểu thức này cho biết in bất kỳ dòng nào bắt đầu bằng một #(và bất cứ thứ gì khác sau nó) HOẶC bất kỳ dòng nào có ký tự bằng 0 giữa đầu và cuối dòng.

Các -vsẽ in trên màn hình các đảo đó, mà sẽ được bất kỳ phù hợp với nhân vật mà không bắt đầu bằng một #.


Nó sẽ không xử lýprint "#tag" # Print a hashtag.
Ray Butterworth

À, đúng rồi ... tất nhiên rồi. Cảm ơn đã chỉ ra rằng. Tôi đang tìm kiếm một câu trả lời liên quan đến các tệp cấu hình linux điển hình, chẳng hạn như cấu hình pam.d, vì vậy tôi đã không nghĩ về điều đó. Tôi đoán nó sẽ phải được điều chỉnh để tìm và xóa bất kỳ bình luận nào nằm trên cùng một dòng với mã. Tôi chỉ thấy có lẽ là một giải pháp tốt hơn cho vấn đề cụ thể của tôi ở trên: egrep -v "# | $ ^"
jackbmg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.