Làm thế nào để viết một tập lệnh bash có các đối số đầu vào tùy chọn?


471

Tôi muốn tập lệnh của mình có thể nhận đầu vào tùy chọn,

ví dụ hiện tại kịch bản của tôi là

#!/bin/bash
somecommand foo

nhưng tôi muốn nói:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]

3
Bash hay POSIX? Với Bash, có nhiều khả năng hơn
user123444555621

@ Pumbaa80 bash - Tôi đã cập nhật các thẻ.
Abe


Câu trả lời:


706

Bạn có thể sử dụng cú pháp giá trị mặc định:

somecommand ${1:-foo}

Ý chí trên, như được mô tả trong Hướng dẫn tham khảo Bash - Mở rộng tham số Shell 3.5.3 [khai thác mỏ nhấn mạnh]:

Nếu tham số không được đặt hoặc null , việc mở rộng từ được thay thế. Mặt khác, giá trị của tham số được thay thế.

Nếu bạn chỉ muốn thay thế một giá trị mặc định nếu tham số không được đặt (nhưng không phải nếu nó là null, ví dụ không phải nếu đó là một chuỗi rỗng), thay vào đó hãy sử dụng cú pháp này:

somecommand ${1-foo}

Một lần nữa từ Hướng dẫn tham khảo Bash - Mở rộng tham số Shell 3.5.3 :

Bỏ qua các kết quả dấu hai chấm trong một thử nghiệm chỉ cho một tham số không được đặt. Nói cách khác, nếu bao gồm dấu hai chấm, toán tử kiểm tra sự tồn tại của cả tham số và giá trị của nó không phải là null; nếu dấu hai chấm bị bỏ qua, toán tử chỉ kiểm tra sự tồn tại.


52
Vui lòng lưu ý sự khác biệt về ngữ nghĩa giữa lệnh trên, "return fooif $1unset hoặc chuỗi rỗng " và ${1-foo}"return fooif $1unset".
l0b0

12
Bạn có thể giải thích tại sao điều này làm việc? Đặc biệt, chức năng / mục đích của ':' và '-' là gì?
jwien001

8
@ jwein001: Trong câu trả lời được gửi ở trên, toán tử thay thế được sử dụng để trả về giá trị mặc định nếu biến không được xác định. Cụ thể, logic là "Nếu $ 1 tồn tại và không rỗng, hãy trả về giá trị của nó; nếu không, hãy trả về foo." Đại tràng là tùy chọn. Nếu nó bị bỏ qua, thay đổi "tồn tại và không null" thành "tồn tại". Dấu trừ chỉ định trả về foo mà không đặt $ 1 bằng 'foo'. Toán tử thay thế là một lớp con của toán tử mở rộng. Xem phần 6.1.2.1 của Robbins và Beebe của cổ điển Shell Scripting [O'Reilly] ( shop.oreilly.com/product/9780596005955.do )
Jubbles

5
@Jubble hoặc nếu bạn không muốn mua toàn bộ sách để tham khảo đơn giản ... tldp.org/LDP/abs/html/parameter-substlation.html
Ohad Schneider

2
Câu trả lời này thậm chí còn tốt hơn nếu nó chỉ ra cách làm cho mặc định là kết quả của việc chạy lệnh, như @hagen làm (mặc dù câu trả lời đó không phù hợp).
sauteman 17/03/2017

310

Bạn có thể đặt giá trị mặc định cho một biến như vậy:

somecommand.sh

#!/usr/bin/env bash

ARG1=${1:-foo}
ARG2=${2:-bar}
ARG3=${3:-1}
ARG4=${4:-$(date)}

echo "$ARG1"
echo "$ARG2"
echo "$ARG3"
echo "$ARG4"

Dưới đây là một số ví dụ về cách thức hoạt động của nó:

$ ./somecommand.sh
foo
bar
1
Thu Mar 29 10:03:20 ADT 2018

$ ./somecommand.sh ez
ez
bar
1
Thu Mar 29 10:03:40 ADT 2018

$ ./somecommand.sh able was i
able
was
i
Thu Mar 29 10:03:54 ADT 2018

$ ./somecommand.sh "able was i"
able was i
bar
1
Thu Mar 29 10:04:01 ADT 2018

$ ./somecommand.sh "able was i" super
able was i
super
1
Thu Mar 29 10:04:10 ADT 2018

$ ./somecommand.sh "" "super duper"
foo
super duper
1
Thu Mar 29 10:05:04 ADT 2018

$ ./somecommand.sh "" "super duper" hi you
foo
super duper
hi
you

2
À, được rồi Tôi -bối rối (có bị phủ nhận không?).
Raffi Khatchadourian

5
Không - đó chỉ là một cách kỳ lạ mà bash có khi thực hiện nhiệm vụ. Tôi sẽ thêm một số ví dụ để làm rõ điều này một chút ... cảm ơn!
Brad

44
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi

1
Về mặt kỹ thuật, nếu bạn chuyển vào một chuỗi trống '' có thể được tính là một tham số, nhưng kiểm tra của bạn sẽ bỏ lỡ nó. Trong trường hợp đó $ # sẽ cho biết có bao nhiêu tham số đã được đưa ra
vmpstr

18
-ncũng giống như ! -z.
l0b0

Tôi nhận được kết quả khác nhau bằng cách sử dụng -n! -zvì vậy tôi sẽ nói rằng đó không phải là trường hợp ở đây.
Eliezer

bởi vì bạn không thể trích dẫn biến, [ -n $1 ] sẽ luôn luôn đúng . Nếu bạn sử dụng bash, [[ -n $1 ]]sẽ hành xử như bạn mong đợi, nếu không bạn phải trích dẫn[ -n "$1" ]
glenn jackman

21

Bạn có thể kiểm tra số lượng đối số với $#

#!/bin/bash
if [ $# -ge 1 ]
then
    $1
else
    foo
fi

10

xin đừng quên, nếu biến của nó $ 1 .. $ n bạn cần ghi vào một biến thông thường để sử dụng thay thế

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}

2
Câu trả lời của Brad ở trên chứng minh rằng các biến đối số cũng có thể được thay thế mà không cần các bình trung gian.
Vadzim

2
+1 để lưu ý cách sử dụng lệnh như ngày làm mặc định thay vì giá trị cố định. Điều này cũng có thể:DAY=${1:-$(date +%F -d "yesterday")}
Garren S

3

Đối với nhiều đối số tùy chọn , bằng cách tương tự với lslệnh có thể lấy một hoặc nhiều tệp hoặc theo mặc định liệt kê mọi thứ trong thư mục hiện tại:

if [ $# -ge 1 ]
then
    files="$@"
else
    files=*
fi
for f in $files
do
    echo "found $f"
done

Không hoạt động chính xác cho các tệp có khoảng trắng trong đường dẫn, than ôi. Chưa tìm ra cách để làm cho công việc đó được nêu ra.


2

Điều này cho phép giá trị mặc định cho đối số 1 tùy chọn và bảo tồn nhiều đối số.

 > cat mosh.sh
   set -- ${1:-xyz} ${@:2:$#} ; echo $*    
 > mosh.sh
   xyz
 > mosh.sh  1 2 3
   1 2 3 

1

Có thể sử dụng thay thế biến để thay thế một giá trị cố định hoặc một lệnh (như date) cho một đối số. Các câu trả lời cho đến nay đã tập trung vào các giá trị cố định, nhưng đây là những gì tôi đã sử dụng để biến ngày thành một đối số tùy chọn:

~$ sh co.sh
2017-01-05

~$ sh co.sh 2017-01-04
2017-01-04

~$ cat co.sh

DAY=${1:-$(date +%F -d "yesterday")}
echo $DAY
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.