Có xargs sử dụng bí danh thay vì nhị phân


13

Bash 4.2 trên CentOS 6.5:

Trong tôi ~/.bash_profilecó một loạt các bí danh, bao gồm:

alias grep='grep -n --color=always'

để tôi có thể tự động tô sáng màu và in số dòng khi chạy grep. Nếu tôi chạy như sau, tô sáng hoạt động như mong đợi:

$ grep -Re 'regex_here' *.py

Tuy nhiên, khi tôi chạy cái này gần đây:

$ find . -name '*.py' | xargs grep -E 'regex_here'

kết quả không được tô sáng và số dòng không được in, buộc tôi phải quay lại và thêm -n --color=alwaysvào greplệnh một cách rõ ràng .

  • Không xargsđọc bí danh trong môi trường?
  • Nếu không, có cách nào để làm cho nó làm điều đó?

Q & A này có những gì bạn muốn.
psimon

@psimon đúng, về cơ bản là nói để làm những gì tôi đã làm trong cách giải quyết của mình - Tôi phải tự mở rộng bí danh của mình trong xargslệnh. Điều tôi đang cố gắng tìm hiểu là liệu có cách nào tôi có thể gọi trực tiếp bí danh của mình không xargs.
MattDMo

1
Bạn đã thử export GREP_OPTIONS='-n --color=always'trước lệnh xargs của bạn chưa?
doneal24

@ DougO'Neal cảm ơn, đã làm việc! Tôi sẽ thêm nó vào của tôi .bash_profile. Hãy viết câu trả lời ...
MattDMo

Câu trả lời:


10

Một bí danh là nội bộ của vỏ nơi nó được xác định. Nó không thể nhìn thấy cho các quá trình khác. Các chức năng vỏ cũng vậy. xargslà một ứng dụng riêng biệt, không phải là trình bao, do đó không có khái niệm bí danh hoặc hàm.

Bạn có thể thực hiện xargs gọi shell thay vì gọi greptrực tiếp. Tuy nhiên, chỉ cần gọi một shell là không đủ, bạn cũng phải xác định bí danh trong shell đó. Nếu bí danh được xác định trong của bạn .bashrc, bạn có thể nguồn tệp đó; tuy nhiên điều này có thể không hoạt động khi bạn .bashrcthực hiện các nhiệm vụ khác không có ý nghĩa trong vỏ không tương tác.

find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E regex_here "$@"' _

Cẩn thận với sự phức tạp của trích dẫn lồng nhau khi gõ regrec. Bạn có thể đơn giản hóa cuộc sống của mình bằng cách chuyển regrec làm tham số cho shell.

find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E "$0" "$@"' regex_here

Bạn có thể thực hiện tra cứu bí danh một cách rõ ràng. Rồi xargssẽ thấy grep -n --color=always.

find . -name '*.py' | xargs "${BASH_ALIASES[grep]}" regex_here

Trong zsh:

find . -name '*.py' | xargs $aliases[grep] regex_here

Nhân tiện, lưu ý rằng find … | xargs … phá vỡ tên tập tin có chứa khoảng trắng (trong số những người khác) . Bạn có thể khắc phục điều này bằng cách thay đổi thành các bản ghi được phân tách bằng null:

find . -name '*.py' -print0 | xargs -0 "${BASH_ALIASES[grep]}" regex_here

hoặc bằng cách sử dụng -exec:

find . -name '*.py' -exec "${BASH_ALIASES[grep]}" regex_here {} +

Thay vì gọi find, bạn có thể làm mọi thứ hoàn toàn bên trong vỏ. Các mẫu toàn cầu **/đi qua các thư mục đệ quy. Trong bash, bạn cần chạy shopt -s globstarđể kích hoạt mẫu hình cầu này trước.

grep regex_here **/*.py

Điều này có một vài hạn chế:

  • Nếu nhiều tệp khớp với nhau (hoặc nếu chúng có đường dẫn dài), lệnh có thể thất bại vì vượt quá độ dài dòng lệnh tối đa.
  • Trong bash .24.2 (nhưng không phải trong các phiên bản gần đây hơn, cũng không phải trong ksh hoặc zsh), **/đệ quy thành các liên kết tượng trưng đến các thư mục.

Một cách tiếp cận khác là sử dụng thay thế quá trình, theo đề xuất của MariusMatutiae .

grep regex_here <(find . -name '*.py')

Điều này hữu ích khi **/không áp dụng được: đối với các findbiểu thức phức tạp hoặc trong bash .24.2 khi bạn không muốn lặp lại theo các liên kết tượng trưng. Lưu ý rằng điều này phá vỡ tên tập tin có chứa khoảng trắng; một cách giải quyết là thiết lập IFSvà vô hiệu hóa toàn cầu , nhưng nó bắt đầu hơi phức tạp:

(IFS=$'\n'; set -f; grep regex_here <(find . -name '*.py') )

cảm ơn bạn đã giải thích rõ ràng lý do tại sao các bí danh không hiển thị với các quy trình khác
MattDMo

Người ta cũng có thể sử dụng thay thế quá trình, xem câu trả lời của tôi.
MariusMatutiae

11

Sử dụng alias xargs='xargs '

alias: alias [-p] [name[=value] ... ]
(snip)
A trailing space in VALUE causes the next word to be checked for
alias substitution when the alias is expanded.

Cảm ơn vì điều đó, tôi đã không biết về trò lừa không gian.
MattDMo

Np. Nó cũng hữu ích với sudo...
1,61803

2

Vui lòng xem đây là một minh chứng cho cách tiếp cận khác mà tôi không thể tìm thấy trong câu hỏi SO liên quan :

Bạn có thể viết hàm bao bọc để xargskiểm tra xem đối số đầu tiên có phải là bí danh không và nếu có, hãy mở rộng nó cho phù hợp.

Đây là một mã thực hiện chính xác điều đó nhưng thật không may, nó yêu cầu trình bao Z và do đó không chạy 1: 1 với bash (và thật lòng mà nói, tôi không quen sử dụng bash đủ để chuyển nó):

xargs () {
        local expandalias
        if [[ $(which $1) =~ "alias" ]]; then
                expandalias=$(builtin alias $1) 
                expandalias="${${(s.'.)expandalias}[2]}"
        else
                expandalias=$1
        fi
        command xargs ${(z)expandalias} "${(z)@[2,-1]}"
}

Bằng chứng, nó hoạt động:

zsh% alias grep = "grep -n" ầm                           # bao gồm số dòng khớp
zsh% tìm foo -name "* .p *" | xargs grep -E test
foo / bar.p0: 151: # data = kiểm tra
foo / bar.p1: 122: # data = test # số dòng được bao gồm
zsh% unalias grep 
zsh% tìm foo -name "* .p *" | xargs grep -E test
foo / bar.p0: # data = kiểm tra
foo / bar.p1: # data = test # số dòng không được bao gồm
zsh% 

1

Một giải pháp đơn giản và thanh lịch hơn là sử dụng thay thế quy trình :

grep -E 'regex_here' <( find . -name '*.py')

Nó không tạo ra một vỏ mới như đường ống, điều đó có nghĩa là bạn vẫn ở trong vỏ ban đầu của mình, nơi bí danh được xác định và đầu ra chính xác là những gì bạn muốn.

Chỉ cần cẩn thận để không có khoảng cách giữa chuyển hướng và dấu ngoặc đơn, nếu không bash sẽ gây ra lỗi. Theo hiểu biết tốt nhất của tôi, sự thay thế quá trình được hỗ trợ bởi Bash, Zsh, Ksh {88,93}, nhưng không phải bởi pdksh (tôi được bảo là chưa nên ).


Tôi nghĩ rằng phát triển pdksh đã chết. Mksh ít nhiều là một dự án kế nhiệm - khá khó khăn, hóa ra (khái niệm phân tích được thực hiện trong đầu của tg @ ') .
Gilles 'SO- ngừng trở nên xấu xa'

Thay thế quy trình là một phương pháp tốt cho các findlệnh phức tạp , mặc dù bạn cần cẩn thận rằng nó sẽ phá vỡ các khoảng trắng và không thể sửa lỗi dễ dàng như find | xargsvậy (bằng cách chuyển sang -print0-0hoặc sử dụng -exec). Khi áp dụng, **/đơn giản và mạnh mẽ hơn.
Gilles 'SO- ngừng trở nên xấu xa'

0

grep sẽ đọc một tập hợp các tùy chọn mặc định từ biến môi trường GREP_OPTIONS. Nếu bạn sẽ đặt

 export GREP_OPTIONS='--line-number --color=always'

trong .bashrc của bạn thì biến sẽ được chuyển sang các mạng con và bạn sẽ nhận được kết quả mà bạn mong đợi.


Nhưng không đặt --line-numberhoặc --color=alwaysvào GREP_OPTIONStrừ khi chỉ với một lệnh, điều này sẽ phá vỡ rất nhiều tập lệnh. --color=autovẫn ổn để có ở đó, và đó là tất cả. Đặt dòng này trong của bạn .bashrcsẽ phá vỡ rất nhiều thứ.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Đặt bất kỳ bí danh hoặc ghi đè tùy chọn mặc định cho bất kỳ lệnh nào cho tài khoản root là một điều xấu. Đặt các tùy chọn này cho tài khoản người dùng không có khả năng gây ra nhiều vấn đề. Tôi không thể đưa ra bất kỳ tập lệnh người dùng nào có vấn đề.
doneal24

Chỉ cần bất kỳ tập lệnh nào sử dụng grep theo cách vượt ra ngoài việc kiểm tra sự hiện diện của sự cố sẽ bị phá vỡ. Ví dụ: từ /etc/init.d/crontrên hệ thống của tôi : value=`egrep "^${var}=" "$ENV_FILE" | tail -n1 | cut -d= -f2` . Hoặc từ /usr/bin/pdfjam: pdftitl=`printf "%s" "$PDFinfo" | grep -e … | sed -e …` . Một bí danh không phải là một vấn đề vì nó không được nhìn thấy trong các tập lệnh.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles Tôi biết nhiều kịch bản như thế này. Những cái tôi không thể nhận được thường chỉ chạy bằng root (như /etc/init.d/cron). Cá nhân, tôi không có bất kỳ bí danh nào được xác định trên tài khoản người dùng của mình và tôi cũng không đặt tùy chọn trong tệp RC hoặc thông qua các biến môi trường để ghi đè hành vi mặc định của các lệnh. Tôi thích dự đoán hơn sự thuận tiện.
doneal24

Bí danh không phá vỡ khả năng dự đoán vì chúng không được nhìn thấy bởi các tập lệnh. Cài đặt GREP_OPTIONSphá vỡ khả năng dự đoán rất tệ, ngoại trừ một vài tùy chọn như --color=auto(đó là những gì nó được thiết kế cho).
Gilles 'SO- đừng trở nên xấu xa'
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.