2010-04-23 44 views
81

Tôi đang viết tập lệnh bash cần lặp qua các đối số được chuyển vào tập lệnh. Tuy nhiên, đối số đầu tiên không được lặp lại, và thay vào đó cần được kiểm tra trước vòng lặp.

Nếu tôi không phải loại bỏ yếu tố đầu tiên tôi chỉ có thể làm:

for item in "[email protected]" ; do 
    #process item 
done 

tôi có thể thay đổi vòng lặp để kiểm tra xem nó trong lần lặp đầu tiên của mình và thay đổi hành vi, nhưng điều đó dường như quá hackish. Có một cách đơn giản để trích xuất đối số đầu tiên ra và sau đó lặp lại phần còn lại, nhưng tôi không thể tìm thấy nó.

Trả lời

96

Sử dụng shift?

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_07.html

Về cơ bản, đọc $1 cho đối số đầu tiên trước khi vòng lặp (hoặc $0 nếu bạn đang muốn kiểm tra là tên kịch bản), sau đó sử dụng shift, sau đó vòng qua còn [email protected].

+5

Xem, tôi biết rằng việc * * đã có một câu trả lời đơn giản. :) – Herms

+0

Đáng được trả lời, nhưng _after_ Câu trả lời của Dennis được chấp nhận :) – mgarciaisaia

+0

@mgarciaisaia có vẻ phù hợp hơn với yêu cầu của OP: * xóa * mục đầu tiên –

28
firstitem=$1 
shift; 
for item in "[email protected]" ; do 
    #process item 
done 
+0

Hãy nhớ rằng '$ 0' nói chung là tên kịch bản. – Amber

+2

+1 để hiển thị một ví dụ đơn giản; lưu ý rằng phần 'in" $ @ "' được ngụ ý và có thể được bỏ qua. – mklement0

+0

@ mklement0 Bạn đang nói rằng bạn chỉ có thể làm "cho mục; làm"? –

91

biến thể khác sử dụng mảng cắt:

for item in "${@:2}" 
do 
    process "$item" 
done 

Điều này có thể hữu ích nếu vì một lý do, bạn muốn rời khỏi lập luận đưa ra từ shift là phá hoại.

+3

Cảm ơn vì $ {@: 2}. Đồ tốt! – spesic

+0

Chính xác những gì tôi muốn. Bây giờ không cần biến temp cho tham số đầu tiên dereferencing trong '" $ {! 1} $ {@: 2} "' –

+0

@Herms này phải là câu trả lời được chấp nhận, dễ đọc hơn và không phá hủy (vs shift) – user1075613

5
q=${@:0:1};[ ${2} ] && set ${@:2} || set ""; echo $q 

EDIT

> q=${@:1} 
# gives the first element of the special parameter array ${@}; but ${@} is unusual in that it contains (? file name or something) and you must use an offset of 1; 

> [ ${2} ] 
# checks that ${2} exists ; again ${@} offset by 1 
    > && 
    # are elements left in  ${@} 
     > set ${@:2} 
     # sets parameter value to ${@} offset by 1 
    > || 
    #or are not elements left in ${@} 
     > set ""; 
     # sets parameter value to nothing 

> echo $q 
# contains the popped element 

Một thí dụ về pop với mảng thường xuyên

LIST=(one two three) 
    ELEMENT=(${LIST[@]:0:1});LIST=("${LIST[@]:1}") 
    echo $ELEMENT 
+0

Vui lòng giải thích mã để mang tính giáo dục hơn. – lpapp

+0

@LaszloPapp, true – Prospero

+0

'q = $ {@: 0: 1}' (btw, bạn giải thích việc đánh giá nó là 'q = $ {@: 1}') phải là 'q = $ {@: 1: 1} 'để rõ ràng hơn:' $ @ 'bắt đầu với chỉ mục * 1 *, có lẽ là song song với' $ 1', '$ 2', ... tham số - phần tử 0 có giá trị _no_ (không giống như đối số rõ ràng của nó,' $ 0', phản ánh tệp shell/script). '[$ {2}]' sẽ _break_ nên '$ 2' chứa các không gian nhúng; bạn sẽ không gặp vấn đề đó nếu bạn sử dụng '[[$ {2}]]' thay thế. Điều đó nói rằng, nhánh có điều kiện và '||' là không cần thiết: nếu chỉ có 1 đối số, '$ {@: 2}' sẽ đơn giản mở rộng đến chuỗi rỗng (tiếp theo). – mklement0

Các vấn đề liên quan