Làm cách nào để grep một dòng cụ thể _and_ dòng đầu tiên của tệp?


76

Giả sử một grep đơn giản như:

$ psa aux | grep someApp
1000     11634 51.2  0.1  32824  9112 pts/1    SN+  13:24   7:49 someApp

Điều này cung cấp nhiều thông tin, nhưng vì dòng đầu tiên của lệnh ps bị thiếu nên không có ngữ cảnh cho thông tin. Tôi muốn rằng dòng đầu tiên của ps cũng được hiển thị:

$ psa aux | someMagic someApp
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000     11634 51.2  0.1  32824  9112 pts/1    SN+  13:24   7:49 someApp

Tất nhiên, tôi có thể thêm regex vào grep đặc biệt cho ps:

$ ps aux | grep -E "COMMAND|someApp"

Tuy nhiên, tôi thích một giải pháp tổng quát hơn vì có những trường hợp khác tôi cũng muốn có dòng đầu tiên.

Có vẻ như đây sẽ là một trường hợp sử dụng tốt cho một mô tả tập tin "stdmeta" .


9
Sự phức tạp được yêu cầu bởi những câu trả lời này cho thấy triết lý Unix "làm một việc và làm tốt" đôi khi làm chúng ta thất bại khi được đo bằng thước đo khả năng sử dụng: biết tất cả các lệnh này đủ để áp dụng chúng cho vấn đề chung này (lọc thông tin quá trình và vẫn nhìn thấy các nhãn cột) cho thấy nhược điểm của cách tiếp cận: đôi khi mọi thứ không khớp với nhau rất sạch sẽ. Đây là lý do tại sao các công cụ như ackrất hữu ích, và tại sao perlquá khứ vọt sed, awkvv phổ biến: điều quan trọng là cho các bộ phận để tổng hợp thành một tổng thể chặt chẽ.
iconoclast

3
tất nhiên, đối với ví dụ cụ thể này, bạn có thể sử dụng -Cđối số psvà bạn sẽ không cần chuyển nó thành grep. ví dụ ps u -C someApphoặc thậm chíps u -C app1 -C app2 -C app3
cas

1
@iconoclast: tất nhiên giải pháp Unixy sẽ là một công cụ có thể ghép nhiều dòng mỗi dòng để được lọc qua các bộ lọc khác nhau. Đây là phiên bản tổng quát ps aux | { head -1; grep foo; }được đề cập bởi @Nahuel Fouilleul bên dưới (đây có lẽ là giải pháp duy nhất mà tôi có thể nhớ lại tại chỗ nếu cần)
Lie Ryan

@iconoclast: Thiếu kinh nghiệm và kiến ​​thức về các công cụ, những gì các công cụ thực sự làm tốt sẽ luôn có vẻ hoàn toàn vô dụng. Biết một lệnh tốt là không có nơi nào có thể sử dụng được, đó là cách đọc hướng dẫn và thực hành tốt. Những công cụ này đã tồn tại trong nhiều thập kỷ. Họ làm việc và phù hợp với nhau rất độc đáo (và sạch sẽ).
Ярослав Рахматуллин

@ Яослав: Tôi nghĩ rằng bạn có thể đã hoàn toàn hiểu sai những gì tôi nói. (Có lẽ vì tiếng Anh không phải là ngôn ngữ đầu tiên của bạn?) "Tính khả dụng" có liên quan đến UX ("trải nghiệm người dùng") không phải là tiện ích (hoặc "tính hữu dụng"). Chỉ ra rằng khi một thao tác đơn giản là phức tạp này, nó làm tổn thương khả năng sử dụng KHÔNG giống như nói các công cụ là vô dụng. Rõ ràng là chúng không vô dụng. Không ai trong tâm trí của họ sẽ nói họ vô dụng.
iconoclast

Câu trả lời:


67

Cách tốt

Thông thường bạn không thể làm điều này với grep nhưng bạn có thể sử dụng các công cụ khác. AWK đã được đề cập nhưng bạn cũng có thể sử dụng sed, như thế này:

sed -e '1p' -e '/youpattern/!d'

Làm thế nào nó hoạt động:

  1. Tiện ích sed hoạt động trên từng dòng riêng lẻ, chạy các lệnh được chỉ định trên mỗi dòng. Bạn có thể có nhiều lệnh, chỉ định một số -etùy chọn. Chúng ta có thể thêm trước mỗi lệnh với một tham số phạm vi chỉ định xem lệnh này có nên được áp dụng cho dòng cụ thể hay không.

  2. "1p" là lệnh đầu tiên. Nó sử dụng plệnh thường in tất cả các dòng. Nhưng chúng tôi cung cấp cho nó một giá trị số chỉ định phạm vi cần áp dụng. Ở đây, chúng tôi sử dụng 1có nghĩa là dòng đầu tiên. Nếu bạn muốn in nhiều dòng, bạn có thể sử dụng x,ypxlà dòng đầu tiên để in, ylà dòng cuối cùng để in. Ví dụ để in 3 dòng đầu tiên, bạn sẽ sử dụng1,3p

  3. Lệnh tiếp theo dthường xóa tất cả các dòng khỏi bộ đệm. Trước lệnh này, chúng tôi đặt yourpatterngiữa hai /ký tự. Đây là một cách khác (đầu tiên là xác định dòng nào như chúng ta đã làm với plệnh) của các dòng địa chỉ mà lệnh sẽ chạy. Điều này có nghĩa là lệnh sẽ chỉ hoạt động cho các dòng phù hợp yourpattern. Ngoại trừ, chúng tôi sử dụng !ký tự trước khi dlệnh đảo ngược logic của nó. Vì vậy, bây giờ nó sẽ loại bỏ tất cả các dòng không khớp với mẫu đã chỉ định.

  4. Cuối cùng, sed sẽ in tất cả các dòng còn lại trong bộ đệm. Nhưng chúng tôi đã xóa các dòng không khớp với bộ đệm để chỉ các dòng phù hợp sẽ được in.

Để tổng hợp: chúng tôi in dòng thứ 1, sau đó chúng tôi xóa tất cả các dòng không khớp với mẫu của chúng tôi khỏi đầu vào. Phần còn lại của dòng được in (để chỉ dòng mà làm phù hợp với mô hình).

Vấn đề đầu tiên

Như đã đề cập trong các ý kiến, có một vấn đề với phương pháp này. Nếu mẫu được chỉ định khớp với dòng đầu tiên, nó sẽ được in hai lần (một lần theo plệnh và một lần vì khớp). Chúng ta có thể tránh điều này theo hai cách:

  1. Thêm 1dlệnh sau 1p. Như tôi đã đề cập, dlệnh xóa các dòng khỏi bộ đệm và chúng tôi chỉ định phạm vi của nó theo số 1, có nghĩa là nó sẽ chỉ xóa dòng thứ nhất. Vì vậy, lệnh sẽ làsed -e '1p' -e '1d' -e '/youpattern/!d'

  2. Sử dụng 1blệnh, thay vì 1p. Đó là một mẹo. blệnh cho phép chúng ta chuyển sang lệnh khác được chỉ định bởi nhãn (cách này có thể bỏ qua một số lệnh). Nhưng nếu nhãn này không được chỉ định (như trong ví dụ của chúng tôi), nó chỉ nhảy đến cuối các lệnh, bỏ qua các lệnh còn lại cho dòng của chúng tôi. Vì vậy, trong trường hợp của chúng tôi, dlệnh cuối cùng sẽ không xóa dòng này khỏi bộ đệm.

Ví dụ đầy đủ:

ps aux | sed -e '1b' -e '/syslog/!d'

Sử dụng dấu chấm phẩy

Một số sedtriển khai có thể giúp bạn tiết kiệm một số thao tác gõ bằng cách sử dụng dấu chấm phẩy để phân tách các lệnh thay vì sử dụng nhiều -etùy chọn. Vì vậy, nếu bạn không quan tâm đến việc di động, lệnh sẽ là ps aux | sed '1b;/syslog/!d'. Nó hoạt động ít nhất trong GNU sedbusyboxthực hiện.

Cách điên

Tuy nhiên, đây là cách khá điên rồ để làm điều này với grep. Nó chắc chắn không tối ưu, tôi đang đăng bài này chỉ cho mục đích học tập, nhưng bạn có thể sử dụng nó chẳng hạn, nếu bạn không có bất kỳ công cụ nào khác trong hệ thống của mình:

ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog'

Làm thế nào nó hoạt động

  1. Đầu tiên, chúng tôi sử dụng -ntùy chọn để thêm số dòng trước mỗi dòng. Chúng tôi muốn đánh số tất cả các dòng chúng tôi phù hợp .*- bất cứ điều gì, thậm chí cả dòng trống. Theo đề xuất trong các nhận xét, chúng tôi cũng có thể khớp '^', kết quả là như nhau.

  2. Sau đó, chúng tôi đang sử dụng các biểu thức chính quy mở rộng để chúng tôi có thể sử dụng \|ký tự đặc biệt hoạt động như OR. Vì vậy, chúng tôi khớp nếu dòng bắt đầu bằng 1:(dòng đầu tiên) hoặc chứa mẫu của chúng tôi (trong trường hợp này là dòng syslog).

Vấn đề về số dòng

Bây giờ vấn đề là, chúng tôi đang nhận được số dòng xấu xí này trong đầu ra của chúng tôi. Nếu đây là một vấn đề, chúng ta có thể loại bỏ chúng bằng cut, như thế này:

ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-

-dtùy chọn chỉ định dấu phân cách, -fchỉ định các trường (hoặc cột) mà chúng tôi muốn in. Vì vậy, chúng tôi muốn cắt từng dòng trên mỗi :ký tự và chỉ in 2 và tất cả các cột tiếp theo. Điều này có hiệu quả loại bỏ cột đầu tiên với dấu phân cách và đây chính xác là những gì chúng ta cần.


4
Việc đánh số dòng cũng có thể được thực hiện cat -nvà sẽ trông rõ ràng hơn như với một grep bị lạm dụng cho việc này.
Alfe

1
nlkhông tính các dòng trống (nhưng in chúng không có số dòng), cat -nđịnh dạng đánh số với các khoảng trắng trước, grep -n .loại bỏ các dòng trống và thêm dấu hai chấm. Tất cả đều có tính năng ... er ... của họ ;-)
Alfe

2
Rất giáo dục trả lời bằng văn bản. Tôi đã cố gắng thay thế "Giả vờ" (Gần đầu) bằng "Chuẩn bị" cho bạn nhưng nó muốn có nhiều thay đổi hơn và tôi không cảm thấy muốn thay đổi tào lao ngẫu nhiên trong bài đăng của mình, vì vậy bạn có thể muốn khắc phục điều đó.
Bill K

2
ps aux | sed '1p;/pattern/!d'sẽ in dòng đầu tiên hai lần nếu nó phù hợp với mẫu . Tốt nhất là sử dụng blệnh : ps aux | sed -e 1b -e '/pattern/!d'. cat -nkhông phải là POSIX. grep -n '^'sẽ đánh số mỗi dòng (không phải là vấn đề đối với đầu ra ps không có dòng trống). nl -ba -d $'\n'số mỗi dòng.
Stéphane Chazelas

2
Lưu ý rằng 1b;...không phải là di động hay POSIX, không thể có bất kỳ lệnh nào khác sau "b", vì vậy bạn cần một dòng mới hoặc biểu thức -e khác.
Stéphane Chazelas

58

Làm thế nào để bạn cảm thấy về việc sử dụng awkthay vì grep?

chopper:~> ps aux | awk 'NR == 1 || /syslogd/'
USER              PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root               19   0.0  0.0  2518684   1160   ??  Ss   26Aug12   1:00.22 /usr/sbin/syslogd
mrb               574   0.0  0.0  2432852    696 s006  R+    8:04am   0:00.00 awk NR == 1 || /syslogd/
  • NR == 1: Số lượng hồ sơ == 1; I E. dòng đầu tiên
  • ||: hoặc là:
  • /syslogd/: Mẫu để tìm kiếm

Nó cũng có thể đáng xem pgrep, mặc dù điều này là nhiều hơn cho các tập lệnh hơn là đầu ra hướng tới người dùng. grepMặc dù vậy, nó sẽ tránh lệnh xuất hiện trong đầu ra.

chopper:~> pgrep -l syslogd
19 syslogd

Rất đẹp, cảm ơn. Đây cũng là kịch bản độc đáo cho việc mở rộng trong tương lai.
dotancohen

Tôi cần phải học cho tôi một số awk. rất đẹp.
dùng606723

30
ps aux | { read line;echo "$line";grep someApp;}

EDIT: sau khi bình luận

ps aux | { head -1;grep someApp;}

Tôi mặc dù head -1sẽ đọc tất cả các đầu vào, nhưng sau khi thử nghiệm nó, nó cũng hoạt động.

{ head -1;grep ok;} <<END
this is a test
this line should be ok
not this one
END

đầu ra là

this is a test
this line should be ok

2
Đó là ý tưởng đánh vần trực tiếp trong bash. Tôi muốn đưa ra nhiều hơn một ngón tay cái cho việc này. Tôi chỉ có thể sử dụng { IFS='' read line; ... }trong trường hợp tiêu đề bắt đầu bằng dấu cách.
Alfe

Điều này chính xác tấn công vấn đề trực tiếp. Đẹp!
dotancohen

3
Tôi chỉ sử dụng head -1thay vì kết hợp đọc / echo.
chepner

1
Vâng, nó hoạt động với head -n1trên bash của tôi. Điều này có thể được thực hiện cụ thể. Đầu tôi không đọc toàn bộ đầu vào trong trường hợp này, chỉ dòng đầu tiên, để lại phần còn lại của chúng trong bộ đệm đầu vào.
Krzysztof Adamski

2
head -n1là ngắn hơn, nhưng nó xuất hiện ngay cả thông số POSIX im lặng về số lượng đầu vào của nó được phép đọc, vì vậy có lẽ read line; echo $linenó dễ mang theo hơn.
chepner

14

Ps hỗ trợ bộ lọc nội bộ,

Giả sử bạn đang tìm kiếm quy trình bash:

ps -C bash -f

Sẽ liệt kê tất cả quá trình mà được đặt tên bash.


Cảm ơn, đó là tốt đẹp để biết. Tuy nhiên, nó sẽ không tìm thấy các kịch bản bắt đầu từ python, trong số những người khác.
dotancohen

6

Tôi có xu hướng gửi tiêu đề đến stderr :

ps | (IFS= read -r HEADER; echo "$HEADER" >&2; cat) | grep ps

Điều này thường là đủ cho mục đích đọc của con người. ví dụ:

  PID TTY          TIME CMD
 4738 pts/0    00:00:00 ps

Phần ngoặc có thể đi vào tập lệnh riêng của nó để sử dụng chung.

Có một tiện ích bổ sung trong đó đầu ra có thể được thêm vào (đến sortv.v.) và tiêu đề sẽ vẫn ở trên đầu.


5

Bạn cũng có thể sử dụng teehead:

ps aux | tee >(head -n1) | grep syslog

Tuy nhiên, lưu ý rằng miễn teelà không thể bỏ qua các SIGPIPEtín hiệu (xem ví dụ như thảo luận ở đây ) phương pháp này cần một cách giải quyết để đáng tin cậy. Cách giải quyết là bỏ qua các tín hiệu SIGPIPE, ví dụ, điều này có thể được thực hiện như thế này trong bash like shell:

trap '' PIPE    # ignore SIGPIPE
ps aux | tee >(head -n1) 2> /dev/null | grep syslog
trap - PIPE     # restore SIGPIPE handling

Cũng lưu ý rằng thứ tự đầu ra không được đảm bảo .


Tôi sẽ không dựa vào điều này để làm việc, lần đầu tiên tôi chạy nó (zsh) nó đã tạo ra các tiêu đề cột dưới kết quả grep. Lần thứ hai thì ổn.
Rqomey

1
Tôi chưa thấy điều này, nhưng một cách để tăng độ tin cậy là chèn một độ trễ nhỏ trong đường ống trước grep: | { sleep .5; cat }.
Thor

2
Thêm giấc ngủ để tránh các vấn đề tương tranh luôn luôn là một hack. Mặc dù điều này có thể hoạt động, đó là một bước về phía bóng tối. -1 cho điều này.
Alfe

1
Tôi đã có một vài vấn đề kỳ lạ khác khi thử câu trả lời này, tôi đã đặt ra một câu hỏi để kiểm tra
Rqomey

Đây là một cách sử dụng tee thú vị, nhưng tôi thấy nó không đáng tin cậy và thường chỉ in dòng đầu ra chứ không in dòng tiêu đề.
dotancohen

4

Có lẽ hai pslệnh sẽ dễ nhất.

$ ps aux | head -1 && ps aux | grep someApp
USER             PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
100         3304   0.0  0.2  2466308   6476   ??  Ss    2Sep12   0:01.75 /usr/bin/someApp

2
Tôi không thích giải pháp này, chủ yếu là vì tình huống có thể thay đổi giữa ps auxcuộc gọi thứ nhất và cuộc gọi thứ hai ... Và nếu bạn chỉ muốn dòng đầu tiên tĩnh đó, tại sao không lặp lại thủ công?
Shadur

1
Thay đổi giữa hai cuộc gọi sẽ không bị làm phiền trong tình huống này . Cái đầu tiên sẽ chỉ cung cấp tiêu đề luôn phù hợp với đầu ra của cái thứ hai.
Alfe

2
Tôi không thấy lý do tại sao điều này bị hạ cấp, nó chắc chắn là một lựa chọn khả thi. Nâng cao.
dotancohen

4

Bạn có thể sử dụng pidstat với:

pidstat -C someApp
or
pidstat -p <PID>

Thí dụ:

# pidstat -C java
Linux 3.0.26-0.7-default (hostname)    09/12/12        _x86_64_

13:41:21          PID    %usr %system  %guest    %CPU   CPU  Command
13:41:21         3671    0.07    0.02    0.00    0.09     1  java

Thông tin thêm: http://linux.die.net/man/1/pidstat


Cảm ơn, đó là tốt đẹp để biết. Tuy nhiên, nó sẽ không tìm thấy các kịch bản bắt đầu từ python, trong số những người khác.
dotancohen

4

Trước tiên hãy đặt tệp sau trong tệp .bashrc hoặc sao chép / dán vào shell để kiểm tra.

function psls { 
ps aux|head -1 && ps aux|grep "$1"|grep -v grep;
}

Cách sử dụng: psls [mẫu grep]

$ psls someApp
USER             PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root              21   0.0  0.0  2467312   1116   ??  Ss   Tue07PM   0:00.17 /sbin/someApp

Đảm bảo nguồn .bashrc của bạn (hoặc .bash_profile nếu bạn đặt nó ở đó thay thế):

source ~/.bashrc

Hàm thậm chí sẽ tự động hoàn thành tại dòng lệnh shell. Như bạn đã nói trong một câu trả lời khác, bạn có thể chuyển dòng đầu tiên vào một tệp để lưu một cuộc gọi vào ps.


1
Thật tuyệt, tôi đã sử dụng loại chức năng đó trong nhiều năm. Tôi gọi phiên bản của mìnhpsl , chỉ gọi psgrepmột lần mỗi phiên bản (và không cần head).
Adam Katz

3

sắp xếp nhưng giữ dòng tiêu đề ở trên cùng

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

Và sử dụng nó như thế này

$ ps aux | body grep someApp
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000     11634 51.2  0.1  32824  9112 pts/1    SN+  13:24   7:49 someApp

Cảm ơn, một số câu trả lời thảo luận về trường hợp chung của câu hỏi này. Hoàn hảo!
dotancohen

3

Cảm ơn chủ yếu là Janis Papanagnou trong comp.unix.shell, tôi sử dụng chức năng sau:

function grep1 {
    IFS= read -r header && printf "%s\n" "$header"; grep "$@"
}

Điều này có một số lợi thế:

  • Hoạt động với bash, zsh, và có lẽ ksh
  • Đây là một thay thế thả xuống cho grep, vì vậy bạn có thể tiếp tục sử dụng bất kỳ cờ nào bạn muốn: -icho kết hợp không phân biệt chữ hoa chữ thường, -Echo các biểu thức mở rộng, v.v.
  • Luôn mang lại mã thoát giống như grep, trong trường hợp bạn muốn xác định theo chương trình xem có dòng nào thực sự khớp không
  • Không in gì nếu đầu vào trống

Ví dụ sử dụng:

$ ps -rcA | grep1 databases
  PID TTY           TIME CMD

$ ps -rcA | grep1 -i databases
  PID TTY           TIME CMD
62891 ??         0:00.33 com.apple.WebKit.Databases

2

Một cách khác với gnu ed:

ed -s '!ps aux' <<< $'2,$v/PATTERN/d\n,p\nq\n'

hoặc, nếu shell hỗ trợ thay thế quá trình:

printf '%s\n' '2,$v/PATTERN/d' ,p q | ed -s <(ps aux)

đó là:

2,$v/PATTERN/d  - remove all lines not matching pattern (ignore the header)
,p              - print the remaining lines
q               - quit

Dễ di chuyển hơn, không có gnu '!' hoặc thay thế vỏ - chỉ sử dụng tích edhợp rđể rđọc đầu ra của ps auxbộ đệm và sau đó xóa các dòng không khớp trong 2,$phạm vi và in kết quả:

printf '%s\n' 'r !ps aux' '2,$v/PATTERN/d' ,p q | ed -s

Và vì các sedlệnh trong đầu ra câu trả lời được chấp nhận cũng là dòng khớp với chính chúng, với một sedhỗ trợ -f-và trình bao hỗ trợ thay thế quy trình, tôi sẽ chạy:

printf '%s\n' '2,${' '/PATTERN/!d' '}' | sed -f - <(ps aux)

mà khá nhiều làm điều tương tự như các edlệnh trước .


1

Cách Perl:

ps aux | perl -ne 'print if /pattern/ || $.==1'

Cách dễ đọc hơn sed, nhanh hơn, không có rủi ro để chọn các dòng không mong muốn.



0

Nếu đó chỉ là cho các quy trình grepping với tiêu đề đầy đủ, tôi sẽ mở rộng đề xuất của @ mrb:

$ ps -f -p $(pgrep bash)
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
nasha     2810  2771  0  2014 pts/6    Ss+    0:00 bash
...

pgrep bash | xargs ps -fpsẽ nhận được kết quả tương tự nhưng không có phần phụ. Nếu định dạng khác là bắt buộc:

$ pgrep bash | xargs ps fo uid,pid,stime,cmd -p
  UID   PID STIME CMD
    0  3599  2014 -bash
 1000  3286  2014 /bin/bash
 ...

-2

Nếu bạn biết số dòng chính xác, thật dễ dàng với perl! Nếu bạn muốn nhận dòng 1 và 5 từ một tệp, hãy nói / etc / passwd:

perl -e 'while(<>){if(++$l~~[1,5]){print}}' < /etc/passwd

Nếu bạn cũng muốn nhận các dòng khác, chỉ cần thêm số của chúng trong mảng.


1
Cảm ơn bạn. Theo OP, tôi biết một số văn bản trong dòng, nhưng không phải là số dòng.
dotancohen

Điều này bật lên như một câu trả lời trên Google khi tìm kiếm trường hợp sử dụng này liên quan chặt chẽ với OP, vì vậy đáng chú ý ở đây.
Dagelf

1
Nếu đó là trường hợp, thì tôi khuyên bạn nên bắt đầu một câu hỏi mới và trả lời nó với câu trả lời này. Hoàn toàn ổn khi trả lời câu hỏi của bạn về SE, đặc biệt là trong tình huống mà bạn đề cập. Hãy tiếp tục và liên kết với câu hỏi mới của bạn trong một nhận xét về OP.
dotancohen

Có những câu hỏi như vậy, nhưng chúng hiện không xuất hiện trên Google.
Dagelf

Dagelf, điểm mấu chốt là - câu trả lời của bạn không trả lời câu hỏi ở đây. @dotancohen đã đúng - nếu điều này bật lên như một câu trả lời trên Google khi tìm kiếm trường hợp sử dụng này liên quan chặt chẽ với OP thì hãy hỏi một câu hỏi riêng - nêu chi tiết trường hợp sử dụng liên quan chặt chẽ đó - và trả lời nó.
don_crissti
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.