Xử lý tất cả các đối số ngoại trừ đối số đầu tiên (trong tập lệnh bash)


444

Tôi có một tập lệnh đơn giản trong đó đối số đầu tiên được dành riêng cho tên tệp và tất cả các đối số tùy chọn khác sẽ được chuyển đến các phần khác của tập lệnh.

Sử dụng Google tôi đã tìm thấy wiki này , nhưng nó cung cấp một ví dụ theo nghĩa đen:

echo "${@: -1}"

Tôi không thể làm gì khác để làm việc, như:

echo "${@:2}"

hoặc là

echo "${@:2,1}"

Tôi nhận được "Thay thế xấu" từ thiết bị đầu cuối.

Vấn đề là gì và làm cách nào tôi có thể xử lý tất cả ngoại trừ đối số đầu tiên được chuyển sang tập lệnh bash?


21
Để gọi cho bất cứ ai khác nhầm lẫn, shebang sai đã được cung cấp gây ra "{@:2}"không hoạt động, đó là lý do tại sao câu trả lời chính xác phù hợp ở trên.
Guvante

3
Bạn vừa sử dụng shell mặc định, đó là dash trên Ubuntu và nhiều Linux khác. Trong dấu gạch ngang "$ {@: -1}" được hiểu là: {tham số: -word} - Sử dụng Giá trị mặc định và sử dụng từ nếu tham số không được xác định hoặc null. Vì vậy, trong dấu gạch ngang "$ {@: -1}" kết quả chính xác giống như "$ @". Để sử dụng bash, chỉ cần sử dụng dòng đầu tiên sau trong tệp tập lệnh: #! / Bin / bash
luart

Câu trả lời:


659

Dùng cái này:

echo "${@:2}"

Cú pháp sau:

echo "${*:2}"

cũng sẽ hoạt động tốt, nhưng không được khuyến khích, vì như @Gordon đã giải thích, rằng bằng cách sử dụng *, nó chạy tất cả các đối số như một đối số duy nhất với khoảng trắng, trong khi @vẫn giữ các khoảng nghỉ giữa chúng (ngay cả khi một số đối số có chứa khoảng trắng ). Nó không tạo ra sự khác biệt với echo, nhưng nó quan trọng đối với nhiều lệnh khác.


7
Tôi chỉ nhận ra shebang của tôi là xấu: #!/usr/bin/env shĐó là lý do tại sao tôi có vấn đề. Ví dụ của bạn hoạt động tốt, giống như đã cung cấp ở trên, sau khi tôi xóa shebang đó
theta

110
Sử dụng "${@:2}"thay vì - sử dụng *chạy tất cả các đối số với nhau như một đối số duy nhất với các không gian, trong khi @bảo tồn vỡ giữa chúng (thậm chí nếu một số các đối số tự chứa khoảng trắng). Sự khác biệt không đáng chú ý echo, nhưng nó quan trọng đối với nhiều thứ khác.
Gordon Davisson

2
@GordonDavisson Toàn bộ vấn đề ở đây là để chạy các đối số cùng nhau. Nếu chúng ta vượt qua tên tập tin, bạn sẽ đúng. echolà đủ tha thứ để nối chúng cho bạn; các lệnh khác có thể không được tốt đẹp. Đừng chỉ cần sử dụng một hay khác: tìm hiểu sự khác biệt giữa *@, và mỗi khi sử dụng. Bạn nên sử dụng chúng như nhau. Một ví dụ điển hình khi điều này sẽ là một vấn đề: nếu $3chứa một ngắt dòng ( \n), nó sẽ được thay thế bằng một khoảng trắng, miễn là bạn có một $IFSbiến mặc định .
Zenexer

1
@Zenexer: Theo tôi hiểu, câu hỏi là làm thế nào để vượt qua tất cả ngoại trừ đối số đầu tiên để "sang phần khác của tập lệnh", echochỉ được sử dụng làm ví dụ - trong trường hợp đó chúng không nên được chạy cùng nhau. Theo kinh nghiệm của tôi, những tình huống mà bạn muốn chúng chạy cùng nhau rất hiếm (xem câu hỏi này để biết một ví dụ ) và "$@"hầu như luôn luôn là những gì bạn muốn. Ngoài ra, vấn đề bạn đề cập với ngắt dòng chỉ xảy ra nếu $@(hoặc $*) không có dấu ngoặc kép.
Gordon Davisson

@GordonDavisson Hmm ... bạn nói đúng, bây giờ tôi nghĩ về nó; ngắt dòng không phải là một vấn đề. Tôi phải đã nghĩ về một cái gì đó khác. Tuy nhiên, tôi vẫn không đồng ý về việc điều hành chúng cùng nhau; Tôi cần sử dụng $*khá thường xuyên trong các kịch bản của tôi.
Zenexer

180

Nếu bạn muốn một giải pháp cũng hoạt động trong /bin/shthử

first_arg="$1"
shift
echo First argument: "$first_arg"
echo Remaining arguments: "$@"

shift [n]thay đổi các tham số vị trí n lần. A shiftđặt giá trị của $1giá trị của $2, giá trị của $2giá trị của $3, v.v., làm giảm giá trị của $#một.


25
+1: Có lẽ bạn nên lưu $ 1 vào một biến trước khi chuyển nó đi.
glenn jackman

3
Đáng ngạc nhiên là foo=shiftkhông làm những gì tôi mong đợi.
Keith Smiley

Tôi biết điều này đã cũ, nhưng hãy thửfoo=$(shift)
raumaan kidwai

12
@raumaankidwai Điều đó không hoạt động vì 2 lý do: 1) shift(trong vỏ) không có bất kỳ đầu ra nào. Nó chỉ loại bỏ $1và thay đổi mọi thứ xuống. 2) $(...)bắt đầu một lớp con, có các đối số cục bộ riêng. Nó thay đổi các đối số trong phần con, không ảnh hưởng đến cha mẹ
Ben Jackson

Cảm ơn :) Có cách nào để làm những gì somecommand "$1" "${@:2}"với phương thức này (tức là thay đổi "nội tuyến") không?
Ẩn danh


0

Đã qua đây để tìm kiếm một cái gì đó khác. Mặc dù bài đăng có vẻ khá cũ, nhưng giải pháp dễ nhất trong bash được minh họa bên dưới (ít nhất là bash 4) bằng cách sử dụng set -- "${@:#}"# là số bắt đầu của phần tử mảng mà chúng ta muốn giữ lại:

    #!/bin/bash

    someVar="${1}"
    someOtherVar="${2}"
    set -- "${@:3}"
    input=${@}

    [[ "${input[*],,}" == *"someword"* ]] && someNewVar="trigger"

    echo -e "${someVar}\n${someOtherVar}\n${someNewVar}\n\n${@}"

Về cơ bản, set -- "${@:3}"chỉ bật ra hai phần tử đầu tiên trong mảng như sự thay đổi của perl và bảo toàn tất cả các phần tử còn lại bao gồm cả phần tử thứ ba. Tôi nghi ngờ có một cách để loại bỏ các yếu tố cuối cùng là tốt.

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.