2014-07-27 16 views
8

Tôi nghĩ rằng xargs là chức năng bản đồ của vỏ UNIX. Chức năng filter là gì?Nếu xargs là bản đồ, bộ lọc là gì?

EDIT: có vẻ như tôi sẽ phải rõ ràng hơn một chút.

Giả sử tôi phải bàn giao một chương trình chấp nhận một chuỗi đơn làm tham số và trả về bằng mã thoát là 0 hoặc 1. Chương trình này sẽ hoạt động như một vị từ trên các chuỗi mà nó chấp nhận.

Ví dụ: tôi có thể quyết định diễn giải tham số chuỗi dưới dạng tệp và xác định biến vị ngữ là "tệp này tồn tại". Trong trường hợp này, chương trình có thể là test -f, trong đó, cho một chuỗi, thoát với 0 nếu tệp tồn tại và 1 cách khác.

Tôi cũng phải truyền một chuỗi các chuỗi. Ví dụ, tôi có thể có một tập tin ~/paths chứa

/etc/apache2/apache2.conf 
/foo/bar/baz 
/etc/hosts 

Bây giờ, tôi muốn tạo một tập tin mới, ~/existing_paths, chỉ chứa những đường dẫn đó tồn tại trên hệ thống tập tin của tôi. Trong trường hợp của tôi, đó sẽ là

/etc/apache2/apache2.conf 
/etc/hosts 

Tôi muốn làm điều này bằng cách đọc trong file ~/paths, lọc những dòng bằng vị test -f, và viết ra để ~/existing_paths. Bằng cách tương tự với xargs, điều này sẽ trông giống như:

cat ~/paths | xfilter test -f > ~/existing_paths 

Đây là chương trình giả thuyết xfilter mà tôi đang tìm kiếm:

xfilter COMMAND [ARG]... 

Trong đó, đối với mỗi dòng L đầu vào tiêu chuẩn của nó, sẽ gọi COMMAND [ARG]... L và nếu mã thoát là 0, nó sẽ in L, nếu không nó sẽ không in được gì.

Để được rõ ràng, tôi không tìm kiếm

  • một cách để lọc một danh sách các filepaths bởi sự tồn tại. Đó là một ví dụ cụ thể.
  • cách viết chương trình như vậy. Tôi có thể làm điều đó.

tôi am tìm kiếm một trong hai:

  • một thực tồn tại trước đó, như xargs, hoặc
  • một lời giải thích rõ ràng về lý do tại sao điều này không tồn tại
+1

Vì không hiệu quả ** fork ** Nt imes một lệnh chỉ filer dựa trên trạng thái thoát. Như bạn đã nói, thật đơn giản để viết bằng bất kỳ ngôn ngữ nào (bash, perl, C) - nhưng không hiệu quả. Hiệu quả hơn nhiều là sử dụng trực tiếp một số lệnh (công cụ thích hợp - dựa trên tình huống) những gì có thể đọc _STDIN_ và _filter input_ như zilion times ** fork/exec ** một lệnh cho trạng thái thoát. Nhiều lần 'xargs' không phải là cách hiệu quả nhất. (Hãy tưởng tượng một danh sách tập tin dài 1_000_000 dòng. Dĩa Milion không phải là điều tốt nhất những gì bạn có thể làm ...) Và nếu cần điều đó (như bạn đã biết) nó là một chức năng bash 3 dòng – jm666

+3

@ jm666 nghe như " hiệu quả "bạn có nghĩa là" biểu diễn ". Tôi không quan tâm đến hiệu suất, tôi quan tâm đến sự biểu cảm. – jameshfisher

Trả lời

1

Bạn có thể có awk thực hiện chức năng filterreduce.

Lọc:

awk 'NR % 2 { $0 = $0 " [EVEN]" } 1' 

Giảm:

awk '{ p = p + $0 } END { print p }' 
+1

Cảm ơn, nhưng 'xargs' có tham số là một lệnh shell chung, đó là hàm để ánh xạ trên các dòng đầu vào. Bằng cách tương tự, 'bộ lọc' nên dùng một lệnh shell để sử dụng như là một vị từ trên các dòng đầu vào (ví dụ, dựa trên mã trả về của nó là 0 hay không). Trong ví dụ của bạn, các biến vị ngữ chỉ được định nghĩa trong 'awk'-speak. – jameshfisher

+0

@jameshfisher Những gì bạn cần là vỏ tôi đoán. – konsolebox

+0

Tôi không chắc chắn ý của bạn là gì - như [this] (http://stackoverflow.com/questions/255898/how-to-iterate-over-arguments-in-bash-script)? – jameshfisher

3

Vì vậy, bạn đang tìm kiếm sự:

reduce( compare( filter(map(.. list())))) 

gì có thể được rewiritten như

list | map | filter | compare | reduce 

Sức mạnh chính của bash là đường ống , do đó không cần phải có một lệnh filter và/hoặcđặc biệt. Trong thực tế hầu hết các unix lệnh có thể hành động trong một (hoặc nhiều hơn) có chức năng như: danh sách

  • đồ
  • lọc
  • giảm

Hãy tưởng tượng:

find mydir -type f -print | xargs grep -H '^[0-9]*$' | cut -d: -f 2 | sort -nr | head -1 
^------list+filter------^ ^--------map-----------^ ^--filter--^ ^compare^ ^reduce^ 

Tạo trường hợp thử nghiệm:

mkdir ./testcase 
cd ./testcase || exit 1 
for i in {1..10} 
do 
    strings -1 < /dev/random | head -1000 > file.$i.txt 
done 
mkdir emptydir 

Bạn sẽ nhận được một thư mục có tên testcase và trong thư mục này 10 tập tin và một thư mục

emptydir file.1.txt file.10.txt file.2.txt file.3.txt file.4.txt file.5.txt file.6.txt file.7.txt file.8.txt file.9.txt 

mỗi tập tin chứa 1000 dòng chuỗi ngẫu nhiên một số dòng đang chứa chỉ số

nay chạy lệnh

find testcase -type f -print | xargs grep -H '^[0-9]*$' | cut -d: -f 2 | sort -nr | head -1 

và bạn sẽ nhận được dòng số lớn nhất từ ​​mỗi tệp như: 42. (Tất nhiên, điều này có thể được thực hiện một cách hiệu quả hơn, đây là chỉ cho demo)

bị phân hủy:

Các find testcase -type f -print sẽ in tất cả các file đơn giản như vậy, DANH (và chỉ giảm xuống tập tin). ouput:

testcase/file.1.txt 
testcase/file.10.txt 
testcase/file.2.txt 
testcase/file.3.txt 
testcase/file.4.txt 
testcase/file.5.txt 
testcase/file.6.txt 
testcase/file.7.txt 
testcase/file.8.txt 
testcase/file.9.txt 

các xargs grep -H '^[0-9]*$' như MAP sẽ chạy một lệnh grep cho mỗi tập tin từ danh sách. Grep thường sử dụng như bộ lọc, ví dụ: command | grep, nhưng bây giờ (với xargs) thay đổi đầu vào (tên tệp) thành (các dòng chỉ chứa chữ số). Đầu ra, nhiều dòng thích:

testcase/file.1.txt:1 
testcase/file.1.txt:8 
.... 
testcase/file.9.txt:4 
testcase/file.9.txt:5 

cấu trúc của dòng: filename colon number, muốn chỉ số để gọi một bộ lọc tinh khiết, những gì dải ra các tên tập tin từ mỗi dòng cut -d: -f2.Nó ra nhiều dòng như:

1 
8 
... 
4 
5 

Bây giờ giảm (nhận được số lượng lớn nhất), các sort -nr loại tất cả số bằng số và đảo ngược trật tự (desc), do đó sản lượng của nó cũng giống như:

42 
18 
9 
9 
... 
0 
0 

và số head -1 in dòng đầu tiên (số lớn nhất).

Tất nhiên, bạn có thể viết danh sách của riêng bạn/lọc/bản đồ/giảm chức năng trực tiếp với bash công trình xây dựng lập trình (vòng, điều kiện và như vậy), hoặc bạn có thể sử dụng bất kỳ ngôn ngữ kịch bản fullblown như perl, ngôn ngữ đặc biệt như awk, sed "ngôn ngữ", hoặc dc (rpn) và như vậy.

Có một bộ lọc đặc biệt lệnh ví dụ:

list | filter_command cut -d: -f 2 

là đơn giản không cần thiết, bởi vì bạn có thể sử dụng trực tiếp các

list | cut 
4

Nếu bản đồ là xargs, lọc ... vẫn còn xargs.

Ví dụ: file danh sách trong thư mục hiện và lọc ra các file không thực thi:

ls | xargs -I{} sh -c "test -x '{}' && echo '{}'" 

Điều này có thể được thực hiện máng tiện dụng một (sản xuất sẵn sàng phi) chức năng:

xfilter() { 
    xargs -I{} sh -c "$* '{}' && echo '{}'" 
} 
ls | xfilter test -x 

Ngoài , bạn có thể sử dụng triển khai bộ lọc song song qua GNU Parallel:

ls | parallel "test -x '{}' && echo '{}'" 
Các vấn đề liên quan