2011-11-28 30 views
99

Cân nhắc lệnh này:Bỏ qua kết quả sản phẩm nào cho xargs

ls /mydir/*.txt | xargs chown root 

Mục đích là để thay đổi chủ sở hữu của tất cả các tập tin văn bản trong mydir để nhổ tận gốc

Vấn đề là nếu không có .txt file trong mydir sau đó xargs đưa ra một lỗi nói rằng không có đường dẫn nào được chỉ định. Đây là một ví dụ vô hại bởi vì một lỗi đang được ném, nhưng trong một số trường hợp, như trong kịch bản mà tôi cần phải sử dụng ở đây, một đường dẫn trống được giả định là thư mục hiện hành. Vì vậy, nếu tôi chạy lệnh đó từ /home/tom/ thì nếu không có kết quả nào cho ls /mydir/*.txt và tất cả các tệp theo /home/tom/ sẽ thay đổi chủ sở hữu của chúng thành thư mục gốc.

Vậy làm cách nào để xargs bỏ qua kết quả trống?

+4

Ngoài: Không bao giờ đầu ra ống từ 'ls' để sử dụng có lập trình; xem http://mywiki.wooledge.org/ParsingLs –

Trả lời

179

Đối với GNU xargs, bạn có thể sử dụng -r hoặc --no-run-if-empty tùy chọn:

--no-run-if-empty
-r
Nếu đầu vào tiêu chuẩn không chứa bất kỳ nonblanks, đừng chạy lệnh. Thông thường, lệnh được chạy một lần ngay cả khi không có đầu vào. Tùy chọn này là một phần mở rộng của GNU.

+6

Tôi thành thật tìm kiếm trong google đầu tiên và tìm thấy điều này (nhưng sẽ không có yêu cầu mà không cần đọc hướng dẫn). Tôi nghĩ đây là hành vi mặc định, không cần chuyển đổi để bật nó. – JonnyJD

+20

Thật không may điều này không hoạt động trên máy Mac. Không phải là lựa chọn ngắn hay dài. – wedi

+4

@wedi - OSX có không gian người dùng BSD, vì vậy loại điều này sẽ xảy ra thường xuyên. Bạn có thể làm việc xung quanh nó bằng cách sử dụng homebrew để cài đặt các tập tin GNU. – edk750

10

man xargs nói --no-run-if-empty.

+0

Nếu bạn đang sử dụng OSX, nó sẽ không hoạt động. edk750 đã giải thích điều này trong bình luận của họ nếu bạn tò mò tại sao. – jasonleonhard

7

Người sử dụng xargs phi GNU có thể tận dụng -L <#lines>, -n <#args>, -i, và -I <string>:

ls /empty_dir/ | xargs -n10 chown root # chown executed every 10 args or fewer 
ls /empty_dir/ | xargs -L10 chown root # chown executed every 10 lines or fewer 
ls /empty_dir/ | xargs -i cp {} {}.bak # every {} is replaced with the args from one input line 
ls /empty_dir/ | xargs -I ARG cp ARG ARG.bak # like -i, with a user-specified placeholder 

Hãy ghi nhớ rằng xargs tách dòng ở khoảng trắng nhưng trích dẫn và thoát có sẵn; RTFM để biết chi tiết.

+0

Dường như không trả lời được câu hỏi? –

+1

@Nicolas: đó là cách để ngăn chặn việc thực hiện nếu phiên bản 'xargs' của bạn không hỗ trợ công tắc' --no-run-if-empty' và cố chạy đối số lệnh mà không có đầu vào STDIN (đây là trường hợp trong Solaris) 10). Các phiên bản trong các bản sao khác có thể bỏ qua một danh sách trống (ví dụ: AIX). – arielCo

+3

Có! Trên MAC OSX, 'echo '' | xargs -n1 echo blah' không làm gì cả; trong khi 'echo 'x' | xargs -n1 echo blah' in "blah". – carlosayam

6

Theo điều khoản của xargs, bạn có thể sử dụng -r như được đề xuất, tuy nhiên nó không được BSD xargs hỗ trợ.

Vì vậy, cách giải quyết bạn có thể vượt qua một số tập tin thêm tạm thời, ví dụ:

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root $(mktemp) 

hoặc chuyển hướng stderr của nó vào null (2> /dev/null), ví dụ

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root 2> /dev/null || true 

Một cách tiếp cận tốt hơn là để lặp qua tìm thấy file sử dụng while loop:

find /mydir -type f -name "*.txt" -print0 | while IFS= read -r -d '' file; do 
    chown -v root "$file" 
done 

Xem thêm: Ignore empty results for xargs in Mac OS X


Cũng xin lưu ý rằng phương pháp của bạn thay đổi quyền không tuyệt vời và không được khuyến khích. Chắc chắn bạn không nên phân tích cú pháp đầu ra của ls command (xem: Why you shouldn't parse the output of ls). Đặc biệt khi bạn đang chạy lệnh của bạn bằng root, bởi vì các tệp của bạn có thể bao gồm các ký tự đặc biệt có thể được diễn giải bởi vỏ hoặc tưởng tượng tệp có ký tự khoảng /, thì kết quả có thể khủng khiếp.

Do đó, bạn nên thay đổi cách tiếp cận của mình và sử dụng lệnh find thay thế, ví dụ:

find /mydir -type f -name "*.txt" -execdir chown root {} ';' 
+0

Xin lỗi, tôi không hiểu cách 'while IFS = read -r -d '' file' hợp lệ. Bạn có thể giải thích? – Adrian

1

Ngày OSX: Bash reimplementation của xargs đối phó với những lập luận -r, đặt rằng ví dụ trong $HOME/bin và thêm nó vào PATH:

#!/bin/bash 
stdin=$(cat <&0) 
if [[ $1 == "-r" ]] || [[ $1 == "--no-run-if-empty" ]] 
then 
    # shift the arguments to get rid of the "-r" that is not valid on OSX 
    shift 
    # wc -l return some whitespaces, let's get rid of them with tr 
    linecount=$(echo $stdin | grep -v "^$" | wc -l | tr -d '[:space:]') 
    if [ "x$linecount" = "x0" ] 
    then 
     exit 0 
    fi 
fi 

# grep returns an error code for no matching lines, so only activate error checks from here 
set -e 
set -o pipefail 
echo $stdin | /usr/bin/xargs [email protected] 
Các vấn đề liên quan