Grep: kết quả bất ngờ khi tìm kiếm các từ trong tiêu đề từ trang man


19

Tôi đang gặp phải hành vi kỳ lạ khi cố gắng grep một trang người đàn ông trên macOS. Ví dụ, trang man Bash rõ ràng có sự xuất hiện của chuỗi NAME:

$ man bash | head -5 | tail -1
NAME

Và nếu tôi grep cho nametôi, tôi nhận được kết quả, nhưng nếu tôi grep cho NAMEtôi thì không:

$ man bash | grep 'NAME'
$ man bash | grep NAME

Tôi đã thử các từ viết hoa khác mà tôi biết có trong đó, và tìm kiếm SHELLkhông BASHmang lại kết quả gì trong khi tìm kiếm kết quả mang lại.

Những gì đang xảy ra ở đây?

Cập nhật : Cảm ơn tất cả các câu trả lời! Tôi nghĩ rằng nó đáng để thêm bối cảnh mà tôi gặp phải điều này. Tôi muốn viết một hàm bash để bọc manvà trong trường hợp tôi đã cố gắng tra cứu trang man cho phần dựng sẵn, hãy chuyển đến phần có liên quan của trang Bash man. Có thể có một cách tốt hơn, nhưng đây là những gì tôi đã có hiện tại:

man () {
  case "$(type -t "$1")" in
    builtin)
      local pattern="^ *$1"

      if bashdoc_match "$pattern \+[-[]"; then
        command man bash | less --pattern="$pattern +[-[]"
      elif bashdoc_match "$pattern\b"; then
        command man bash | less --pattern="$pattern[[:>:]]"
      else
        command man bash
      fi
      ;;
    keyword)
      command man bash | less --hilite-search --pattern='^SHELL GRAMMAR$'
      ;;
    *)
      command man "$@"
      ;;
  esac
}

bashdoc_match() {
  command man bash | col -b | grep -l "$1" > /dev/null
}


Bạn đang sử dụng hệ điều hành nào? Tôi chắc chắn câu trả lời được chấp nhận là đúng nhưng IO không thể sao chép câu này trên hộp Arch Linux của tôi. man bash | grep NAMEhoạt động như mong đợi.
terdon

@terdon Tôi đang dùng macOS. Tôi có hành vi này với Bash 3.2 và 4.4.5
ivan

Chỉ là một bên: nếu bạn phát hiện một nội dung, bạn chỉ có thể sử dụng helplệnh bash để lấy thông tin của nó.
Joe

@Joe Vấn đề là tôi thường thấy helpkết quả bỏ quá nhiều. Kiểm tra help completeso với completephần trong man bash, ví dụ.
ivan

Câu trả lời:


33

Nếu bạn thêm một lệnh | sed -n lđó tail, để hiển thị các ký tự không in được, có thể bạn sẽ thấy một cái gì đó như:

N\bNA\bAM\bME\bE

Đó là, mỗi ký tự được viết là XBackspace X. Trên các thiết bị đầu cuối hiện đại, ký tự cuối cùng được viết lên chính nó (vì Backspace aka BS aka \baka ^Hlà ký tự di chuyển con trỏ một cột sang trái) không có sự khác biệt. Nhưng trong các máy đánh chữ cổ, điều đó sẽ khiến nhân vật xuất hiện in đậm vì nó tốn gấp đôi mực.

Tuy nhiên, các máy nhắn tin thích more/ lesskhông hiểu định dạng đó có nghĩa là in đậm, vì vậy đó vẫn là những gì roffđể xuất văn bản in đậm.

Một số triển khai của con người sẽ gọi rofftheo cách mà các chuỗi đó không được sử dụng (hoặc gọi nội bộ col -b -p -xđể loại bỏ chúng như trong trường hợp man-dbthực hiện (trừ khi MAN_KEEP_FORMATTINGbiến môi trường được đặt)) và không gọi máy nhắn tin khi chúng phát hiện đầu ra sẽ không đến một thiết bị đầu cuối (vì vậy man bash | grep NAMEsẽ làm việc ở đó), nhưng không phải là của bạn.

Bạn có thể sử dụng col -bđể loại bỏ các chuỗi đó (có các loại khác ( _BS X) cũng như gạch chân).

Đối với các hệ thống sử dụng GNU roff(như GNU hoặc FreeBSD), bạn có thể tránh các chuỗi đó được sử dụng ở nơi đầu tiên bằng cách đảm bảo các -c -b -utùy chọn được chuyển đến grotty, ví dụ bằng cách đảm bảo các -P-cbutùy chọn được chuyển đến groff.

Chẳng hạn, bằng cách tạo một tập lệnh bao bọc groffcó tên :

#! /bin/sh -
exec /usr/bin/groff -P-cbu "$@"

Mà bạn đặt trước / usr / bin / groff in $PATH.

Với macOS ' man(cũng sử dụng GNU roff), bạn có thể tạo một man-no-overstrike.conf:

NROFF /usr/bin/groff -mandoc -Tutf8 -P-cbu

Và gọi manlà:

man -C man-no-overstrike.conf bash | grep NAME

Vẫn với GNU roff, nếu bạn đặt GROFF_SGRbiến môi trường (hoặc không đặt GROFF_NO_SGRbiến tùy thuộc vào cách đặt mặc định tại thời điểm biên dịch), thì grotty(miễn là nó không được thông qua -ctùy chọn) sẽ sử dụng các chuỗi thoát thiết bị đầu cuối ANSI SGR thay thế của những thủ thuật BS cho các thuộc tính nhân vật. lesshiểu chúng khi được gọi với -Rtùy chọn.

Người đàn ông của FreeBSD gọi grottyvới -ctùy chọn trừ khi bạn yêu cầu màu bằng cách đặt biến MANCOLOR (trong trường hợp -cnày không được chuyển đến grottygrottytrở về mặc định sử dụng chuỗi thoát ANR SGR ở đó).

MANCOLOR=1 man bash | grep NAME

sẽ làm việc ở đó

Trên Debian, GROFF_SGR không phải là mặc định. Nếu bạn làm:

GROFF_SGR=1 man bash | grep NAME

tuy nhiên, vì manthiết bị xuất chuẩn không phải là thiết bị đầu cuối, nên nó cũng tự chuyển nó sang một GROFF_NO_SGRbiến grotty(tôi cho rằng nó có thể sử dụng col -bpxđể loại bỏ các chuỗi BS vì colkhông biết cách loại bỏ các chuỗi SGR, mặc dù nó vẫn còn nó với MAN_KEEP_FORMATTING) mà ghi đè của chúng tôi GROFF_SGR. Bạn có thể làm thay thế:

GROFF_SGR=1 MANPAGER='grep NAME' man bash

(trong một thiết bị đầu cuối) để có các chuỗi thoát SGR.

Lúc đó, bạn sẽ nhận thấy rằng một số TÊN đó xuất hiện in đậm trên thiết bị đầu cuối (và trong less -Rmáy nhắn tin). Nếu bạn cung cấp đầu ra cho sed -n l( MANPAGER='sed -n /NAME/l'), bạn sẽ thấy một cái gì đó như:

\033[1mNAME\033[0m$

Trường hợp \e[1mtrình tự bật đậm trong các thiết bị đầu cuối tương thích ANSI và \e[0mtrình tự hoàn nguyên tất cả các thuộc tính SGR về mặc định.

Trên văn bản đó grep NAMEhoạt động như văn bản đó có chứa NAME, nhưng bạn vẫn có thể gặp vấn đề nếu tìm kiếm văn bản chỉ có các phần của nó được in đậm / gạch chân ...


2
Wow, khá thú vị để xem di sản của loại tele vật lý ở đó. Hai lần càng nhiều mực => đậm. Làm cho cảm giác hoàn hảo
ivan

1
Tôi đang yêu sed -n lnhư một sự thay thế cho od.
Tom Hale

13

Nếu bạn nhìn vào bất kỳ trang thủ công nào, bạn sẽ nhận thấy rằng các tiêu đề được in đậm. Điều này đạt được thông qua định dạng chúng với các ký tự điều khiển. Để có thể grepthích bạn muốn, những thứ này phải được loại bỏ.

Các coltiện ích có thể được sử dụng cho việc này:

$ man bash | col -b | grep 'NAME'

Các -btùy chọn có mô tả sau đây trên OpenBSD :

Không xuất bất kỳ khoảng trống nào, chỉ in ký tự cuối cùng được ghi vào từng vị trí cột. Điều này có thể hữu ích trong việc xử lý đầu ra của mandoc (1).


Linux colhướng dẫn sử dụng (trên Ubuntu) không có câu cuối cùng trong đó (nhưng nó hoạt động theo cùng một cách).

Trên Linux, việc bỏ đặt MAN_KEEP_FORMATTINGbiến môi trường (hoặc đặt nó thành một chuỗi trống) cũng có thể giúp ích và sẽ cho phép bạn grepmà không cần chuyển đầu ra manthông qua col -b.


Tôi nghĩ (như tôi đã thử nghiệm điều này trên Arch và hệ thống Ubuntu) rằng trên Linux điều này không cần thiết, hoặc không còn nữa. Trên cả hai hệ thống, NAMEhướng dẫn sử dụng bash chỉ là NAMEkhông \b.
terdon

@terdon Tôi không phát hiện ra việc đề cập đến macOS trước tiên, vì vậy tôi cho rằng một hệ thống Linux được cấu hình sai là một khả năng. Bây giờ tôi đã cắt bớt các bit Linux.
Kusalananda

Bạn không bỏ lỡ điều gì, tôi đã hỏi OP họ đang sử dụng HĐH nào vì tôi không thể sao chép trên Linux, họ nói macOS và tôi mới thêm nó ngay bây giờ. Và tôi đã không ngụ ý rằng bạn đã sai, vì tất cả những gì tôi biết đều có các bản phân phối Linux ngoài kia, nơi MAN_KEEP_FORMATTINGbiến số hoạt động chính xác như bạn nói. Tôi chỉ muốn chỉ ra rằng đó không phải là trường hợp luôn luôn.
terdon
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.