Tạo một bí danh Bash có tham số?


1273

Tôi đã từng sử dụng CShell (), cho phép bạn tạo một bí danh có tham số. Ký hiệu là một cái gì đó như

alias junk="mv \\!* ~/.Trash"

Trong Bash, điều này dường như không hoạt động. Cho rằng Bash có vô số tính năng hữu ích, tôi sẽ cho rằng cái này đã được triển khai nhưng tôi tự hỏi làm thế nào.



2
Hãy chắc chắn rằng bạn sử dụng các trích dẫn xung quanh các cuộc tranh luận"$1"
Barshe Roussy

Câu hỏi này không có chủ đề cho SO. Nó được trả lời trên UNIX.SE , và câu trả lời là bạn thậm chí không cần phải bận tâm: "Ví dụ, nếu bạn đã bí danh lsđể ls -la, sau đó gõ ls foo barsẽ thực sự thực hiện ls -la foo bar. Trên dòng lệnh"
Dan Dascalescu

7
điều đó sẽ không giúp ích gì cho việc nội suy một biến vào giữa chuỗi
Franz Sittampalam

1
Đây là bí danh thử nghiệm lil mà tôi đã sử dụng để khám phá sai lầm này ... alias test_args="echo PREFIX --$1-- SUFFIX", khi được gọi với test_args ABCDnăng suất đầu ra giao diện điều khiển sauPREFIX ---- SUFFIX ABCD
jxramos

Câu trả lời:


2124

Bí danh Bash không trực tiếp chấp nhận tham số. Bạn sẽ phải tạo một chức năng.

aliaskhông chấp nhận tham số nhưng một hàm có thể được gọi giống như bí danh. Ví dụ:

myfunction() {
    #do things with parameters like $1 such as
    mv "$1" "$1.bak"
    cp "$2" "$1"
}


myfunction old.conf new.conf #calls `myfunction`

Nhân tiện, các hàm Bash được định nghĩa trong .bashrccác tệp của bạn và các tệp khác có sẵn dưới dạng các lệnh trong trình bao của bạn. Vì vậy, ví dụ bạn có thể gọi hàm trước đó như thế này

$ myfunction original.conf my.conf

48
Tôi có nên bọc $1trong dấu ngoặc kép?
Jürgen Paul

263
Bạn thậm chí không phải khai báo bí danh. Chỉ cần xác định chức năng sẽ làm.
dinigo

207
Nếu bạn đang thay đổi bí danh thành một hàm, sourceing .bashrc của bạn sẽ thêm chức năng đó nhưng nó sẽ không làm thay đổi bí danh cũ. Vì bí danh là tiền lệ cao hơn các hàm, nên nó sẽ cố gắng sử dụng bí danh. Bạn cần phải đóng và mở lại vỏ của bạn, hoặc cuộc gọi khác unalias <name>. Có lẽ tôi sẽ cứu ai đó trong 5 phút tôi vừa lãng phí.
Marty Neal

55
@MartinNeal: Một mẹo tiết kiệm thời gian tôi học được ở Sun là chỉ cần thực hiện exec bash: Nó sẽ khởi động một lớp vỏ mới, cho bạn đọc rõ các cấu hình của mình, giống như khi bạn đóng và mở lại, nhưng cũng giữ các cài đặt biến môi trường của phiên đó . Ngoài ra, thực thi bashmà không có thực thi có thể hữu ích khi bạn muốn xử lý suy nghĩ như một ngăn xếp.
Macneil Shonle

21
@mich - vâng, luôn đặt các biến bash trong dấu ngoặc kép. ví dụ mv "$1" "$1.bak". không có dấu ngoặc kép, nếu $ 1 là "hello world", bạn sẽ thực thi mv hello world hello world.bakthay vì mv "hello world" "hello world.bak".
orion elenzil

208

Tinh chỉnh câu trả lời ở trên, bạn có thể nhận được cú pháp 1 dòng giống như bạn có thể cho các bí danh, thuận tiện hơn cho các định nghĩa đặc biệt trong tệp shell hoặc .bashrc:

bash$ myfunction() { mv "$1" "$1.bak" && cp -i "$2" "$1"; }

bash$ myfunction original.conf my.conf

Đừng quên dấu chấm phẩy trước dấu ngoặc phải. Tương tự, đối với câu hỏi thực tế:

csh% alias junk="mv \\!* ~/.Trash"

bash$ junk() { mv "$@" ~/.Trash/; }

Hoặc là:

bash$ junk() { for item in "$@" ; do echo "Trashing: $item" ; mv "$item" ~/.Trash/; done; }

3
Tôi thích câu trả lời này, vì nó cho thấy việc lặp qua các đối số có thể xuất hiện. $ 1 và $ 2 chỉ là những trường hợp đặc biệt, cũng được minh họa trong câu trả lời này.
philo vivero

16
Thay đổi mv "$1" "$1.bak"; cp "$2" "$1" thành mv "$1" "$1.bak" && cp "$2" "$1"để không bị mất dữ liệu của bạn khi mvchạy vào rắc rối (ví dụ, hệ thống tập tin đầy đủ).
Henk Langeveld

3
"Đừng quên dấu chấm phẩy trước dấu ngoặc phải." Nhiều lần thế này! Cảm ơn :)
Kaushal Modi

Và các khoảng trắng sau dấu ngoặc đầu tiên và trước dấu ngoặc cuối cùng cũng được yêu cầu.
Nhà nguyện Bryan

1
@HenkLangeveld Mặc dù nhận xét của bạn là hoàn toàn chính xác nhưng điều đó cho thấy rằng bạn đã ở đây được một thời gian - Tôi không biết khi nào tôi gặp phải lỗi "không còn chỗ trống trên thiết bị" ;-). (Tôi sử dụng nó thường xuyên mặc dù khi tôi không tìm thấy không gian trên kệ bếp nữa!) Dường như không xảy ra rất thường xuyên trong những ngày này.
Peter - Phục hồi Monica

124

Câu hỏi đơn giản là hỏi sai. Bạn không tạo bí danh lấy tham số vì aliaschỉ cần thêm tên thứ hai cho thứ đã tồn tại. Chức năng mà OP muốn là functionlệnh tạo ra một chức năng mới. Bạn không cần đặt bí danh cho hàm vì hàm đã có tên.

Tôi nghĩ rằng bạn muốn một cái gì đó như thế này:

function trash() { mv "$@" ~/.Trash; }

Đó là nó! Bạn có thể sử dụng các tham số $ 1, $ 2, $ 3, v.v. hoặc chỉ nhồi tất cả chúng với $ @


7
Câu trả lời này nói lên tất cả. Nếu tôi đọc từ dưới cùng của trang này, tôi đã tiết kiệm được một chút thời gian.
joe

-1 Một bí danh và một chức năng không tương đương ...echo -e '#!/bin/bash\nshopt -s expand_aliases\nalias asrc='\''echo "${BASH_SOURCE[0]}"'\'' # note the '\''s\nfunction fsrc(){ echo "${BASH_SOURCE[0]}";}'>>file2&&echo -e '#!/bin/bash\n. file2\nalias rl='\''readlink -f'\''\nrl $(asrc)\nrl $(fsrc)'>>file1&&chmod +x file1&&./file1;rm -f file1 file2
Logic mờ

Bạn thực sự nên trích dẫn $@để hỗ trợ tên tệp có dấu cách, v.v.
Tom Hale

Nó được cho là một lời giải thích chung rằng bạn không có các tham số bí danh, thay vào đó bạn sử dụng một hàm. Hàm đã cho chỉ là một ví dụ để chống lại ví dụ ban đầu. Tôi không nghĩ rằng người đó đang tìm kiếm một chức năng rác mục đích chung. Tuy nhiên, vì muốn trình bày mã tốt hơn, tôi đã cập nhật câu trả lời.
Evan Langlois

1
@FuzzyLogic - Tôi đã dành vài phút để giải nén mã trong bình luận của bạn. Đó là rất nhiều nỗ lực (thú vị) để trải qua để đóng gói một số mã vào một nhận xét mà bạn không thể định dạng đúng. Tôi vẫn chưa tìm ra chính xác những gì nó làm hoặc quan trọng hơn, tại sao nó hỗ trợ khẳng định (chính xác) của bạn.
Joe

110

TL; DR: Thay vào đó

Nó dễ dàng hơn và dễ đọc hơn để sử dụng một hàm so với bí danh để đặt các đối số ở giữa một lệnh.

$ wrap_args() { echo "before $@ after"; }
$ wrap_args 1 2 3
before 1 2 3 after

Nếu bạn đọc tiếp, bạn sẽ học được những điều mà bạn không cần biết về xử lý đối số shell. Kiến thức là nguy hiểm. Chỉ cần có được kết quả mà bạn muốn, trước khi mặt tối mãi mãi kiểm soát số phận của bạn.

Làm rõ

bashbí danh không chấp nhận đối số, nhưng chỉ ở cuối :

$ alias speak=echo
$ speak hello world
hello world

Đặt các đối số vào giữa lệnh thông qua aliaslà thực sự có thể nhưng nó trở nên xấu xí.

Đừng thử điều này ở nhà, những đứa trẻ!

Nếu bạn thích phá vỡ các giới hạn và làm những gì người khác nói là không thể, thì đây là công thức. Đừng trách tôi nếu tóc bạn bị xơ và mặt bạn bị che phủ theo kiểu nhà khoa học điên cuồng.

Cách giải quyết là chuyển các đối số aliaschỉ chấp nhận ở cuối cho một trình bao bọc sẽ chèn chúng vào giữa và sau đó thực hiện lệnh của bạn.

Giải pháp 1

Nếu bạn thực sự không sử dụng chức năng mỗi lần, bạn có thể sử dụng:

$ alias wrap_args='f(){ echo before "$@" after;  unset -f f; }; f'
$ wrap_args x y z
before x y z after

Bạn có thể thay thế $@bằng $1nếu bạn chỉ muốn đối số đầu tiên.

Giải thích 1

Điều này tạo ra một hàm tạm thời f, được thông qua các đối số (lưu ý fđược gọi ở cuối). Việc unset -fxóa định nghĩa hàm khi bí danh được thực thi để nó không bị treo xung quanh sau đó.

Giải pháp 2

Bạn cũng có thể sử dụng một subshell:

$ alias wrap_args='sh -c '\''echo before "$@" after'\'' _'

Giải thích 2

Bí danh xây dựng một lệnh như:

sh -c 'echo before "$@" after' _

Bình luận:

  • Giữ chỗ _là bắt buộc, nhưng nó có thể là bất cứ điều gì. Nó được thiết lập để sh's $0, và được yêu cầu để là người đầu tiên trong những lập luận do người dùng đưa không được tiêu thụ. Trình diễn:

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
  • Các dấu ngoặc đơn bên trong dấu ngoặc đơn là bắt buộc. Đây là một ví dụ về nó không hoạt động với dấu ngoặc kép:

    $ sh -c "echo Consumed: $0 Printing: $@" alcohol drunken babble
    Consumed: -bash Printing:

    Ở đây các giá trị của shell tương tác $0$@được thay thế thành dấu ngoặc kép trước khi nó được chuyển đến sh. Đây là bằng chứng:

    echo "Consumed: $0 Printing: $@"
    Consumed: -bash Printing:

    Các trích dẫn duy nhất đảm bảo rằng các biến này không được giải thích bởi shell tương tác và được truyền theo nghĩa đen sh -c.

    Bạn có thể sử dụng dấu ngoặc kép và \$@, nhưng cách tốt nhất là trích dẫn các đối số của bạn (vì chúng có thể chứa dấu cách) và \"\$@\"trông thậm chí xấu hơn, nhưng có thể giúp bạn giành chiến thắng trong một cuộc thi giấu giếm trong đó mái tóc xơ rối là điều kiện tiên quyết để tham gia.


2
đối với giải pháp 1, hãy đảm bảo bạn sử dụng các trích dẫn đơn và tránh \ "trong khoảng $ @. Một kỹ thuật rất hữu ích nếu bạn cần nó. ty.
sgtz

Giải pháp 1 làm việc cho tôi bọc rdesktop-vrdp với đối số cho mỗi máy chủ tôi muốn.
Hsehdar

Chấp nhận các đối số ở cuối là chính xác những gì tôi cần để thay thế "git checkout {Branchname}" bằng một "gc {Branchname}" đơn giản. Trong .bash_profile tôi chỉ cần thêmalias gc='git checkout'
AbstractVoid

@sgtz tại sao bạn muốn xóa dấu ngoặc kép $@? Chúng là cần thiết nếu bạn có, ví dụ, các tệp có khoảng trắng trong đó.
Tom Hale

@TomHale Đây là một số ngôn ngữ học, nhưng giải pháp 1 không thực sự hữu ích nếu ai đó thực sự chống lại việc sử dụng một chức năng (vì bất kỳ lý do gì có thể) vì bạn trực tiếp thừa nhận rằng bạn chỉ chuyển định nghĩa của chức năng sang thời gian thực hiện bí danh. thứ hai, "các bí danh bash không chấp nhận các đối số, nhưng chỉ ở cuối" là nhiều ngữ nghĩa hơn: các bí danh được thay thế theo định nghĩa của các từ theo chuỗi. tuy nhiên họ không cần chấp nhận các đối số, các lệnh được thực thi thông qua thay thế có thể. bí danh là một nhân vật thay thế, không hơn, không kém. Không?
BUFU

39

Một giải pháp thay thế là sử dụng điểm đánh dấu , một công cụ tôi đã tạo gần đây cho phép bạn "đánh dấu" các mẫu lệnh và dễ dàng đặt con trỏ tại các vị trí giữ lệnh:

đánh dấu dòng lệnh

Tôi thấy rằng hầu hết thời gian, tôi đang sử dụng các hàm shell nên tôi không phải viết đi viết lại các lệnh được sử dụng thường xuyên trong dòng lệnh. Vấn đề của việc sử dụng các hàm cho trường hợp sử dụng này, là thêm các thuật ngữ mới vào từ vựng lệnh của tôi và phải nhớ những tham số chức năng nào đề cập đến trong lệnh thực. Mục tiêu đánh dấu là để loại bỏ gánh nặng tinh thần đó.


14

Tất cả bạn phải làm là tạo một hàm bên trong một bí danh:

$ alias mkcd='_mkcd(){ mkdir "$1"; cd "$1";}; _mkcd'

Bạn phải đặt dấu ngoặc kép quanh "$ 1" vì dấu ngoặc đơn sẽ không hoạt động.


5
Điều đó thật thông minh, nhưng khác với thực tế là câu hỏi đã chỉ định tạo bí danh, có lý do nào để không tạo ra hàm có cùng tên với bí danh ban đầu không?
xaxxon

1
@xaxxon Không thực sự, nhưng đó là cách dễ nhất mà tôi biết để sử dụng bí danh, không phải chức năng.
Ken Trần

1
Điều này không hoạt động. Trên Ubuntu 18, tôi gặp lỗi bash: syntax error near unexpected token '{mkdir'.
Shital Shah

thiếu một dấu vết ;bên trong hàm _mkcdrất có thể là lỗi từ đó.
Jetchisel

Để lại không gian trước và sau {}
hesham_EE

10

Đây là ba ví dụ về các hàm tôi có trong ~/.bashrcđó, về cơ bảncác bí danh chấp nhận một tham số:

#Utility required by all below functions.
#/programming/369758/how-to-trim-whitespace-from-bash-variable#comment21953456_3232433
alias trim="sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'"

.

:<<COMMENT
    Alias function for recursive deletion, with are-you-sure prompt.

    Example:
        srf /home/myusername/django_files/rest_tutorial/rest_venv/

    Parameter is required, and must be at least one non-whitespace character.

    Short description: Stored in SRF_DESC

    With the following setting, this is *not* added to the history:
        export HISTIGNORE="*rm -r*:srf *"
    - https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash

    See:
    - y/n prompt: https://stackoverflow.com/a/3232082/2736496
    - Alias w/param: https://stackoverflow.com/a/7131683/2736496
COMMENT
#SRF_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
SRF_DESC="srf [path]: Recursive deletion, with y/n prompt\n"
srf()  {
    #Exit if no parameter is provided (if it's the empty string)
        param=$(echo "$1" | trim)
        echo "$param"
        if [ -z "$param" ]  #http://tldp.org/LDP/abs/html/comparison-ops.html
        then
          echo "Required parameter missing. Cancelled"; return
        fi

    #Actual line-breaks required in order to expand the variable.
    #- https://stackoverflow.com/a/4296147/2736496
    read -r -p "About to
    sudo rm -rf \"$param\"
Are you sure? [y/N] " response
    response=${response,,}    # tolower
    if [[ $response =~ ^(yes|y)$ ]]
    then
        sudo rm -rf "$param"
    else
        echo "Cancelled."
    fi
}

.

:<<COMMENT
    Delete item from history based on its line number. No prompt.

    Short description: Stored in HX_DESC

    Examples
        hx 112
        hx 3

    See:
    - https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
COMMENT
#HX_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
HX_DESC="hx [linenum]: Delete history item at line number\n"
hx()  {
    history -d "$1"
}

.

:<<COMMENT
    Deletes all lines from the history that match a search string, with a
    prompt. The history file is then reloaded into memory.

    Short description: Stored in HXF_DESC

    Examples
        hxf "rm -rf"
        hxf ^source

    Parameter is required, and must be at least one non-whitespace character.

    With the following setting, this is *not* added to the history:
        export HISTIGNORE="*hxf *"
    - https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash

    See:
    - https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
COMMENT
#HXF_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
HXF_DESC="hxf [searchterm]: Delete all history items matching search term, with y/n prompt\n"
hxf()  {
    #Exit if no parameter is provided (if it's the empty string)
        param=$(echo "$1" | trim)
        echo "$param"
        if [ -z "$param" ]  #http://tldp.org/LDP/abs/html/comparison-ops.html
        then
          echo "Required parameter missing. Cancelled"; return
        fi

    read -r -p "About to delete all items from history that match \"$param\". Are you sure? [y/N] " response
    response=${response,,}    # tolower
    if [[ $response =~ ^(yes|y)$ ]]
    then
        #Delete all matched items from the file, and duplicate it to a temp
        #location.
        grep -v "$param" "$HISTFILE" > /tmp/history

        #Clear all items in the current sessions history (in memory). This
        #empties out $HISTFILE.
        history -c

        #Overwrite the actual history file with the temp one.
        mv /tmp/history "$HISTFILE"

        #Now reload it.
        history -r "$HISTFILE"     #Alternative: exec bash
    else
        echo "Cancelled."
    fi
}

Người giới thiệu:


Huh? Đó là một chức năng, không phải bí danh. Và một trong những tài liệu tham khảo của bạn là câu hỏi này.
tripleee

2
Không, nó hoạt động chính xác như một chức năng. Giống như một số câu trả lời ở đây giải thích, bạn không thể tạo bí danh lấy tham số. Những gì bạn có thể làm là viết một hàm, đó là những gì bạn đã làm.
tripleee

1
@tripleee Từ quan điểm bash newbie của tôi, trước khi đọc bình luận của bạn, tôi nghĩ đó là một bí danh (một cách khác để tạo một cái). Nó hoạt động chính xác như một, như tôi có thể nói. Nó thực chất là một bí danh chấp nhận một tham số, ngay cả khi tôi không sử dụng thuật ngữ này. Tôi không thấy vấn đề. Tôi đã làm rõ liên kết đến câu trả lời khác trong vấn đề này. Nó giúp tôi tạo ra thứ này.
aliteralmind

1
Có lẽ điều này không trả lời cụ thể câu hỏi "một bí danh bash chấp nhận một tham số", bởi vì bây giờ tôi hiểu rằng điều đó là không thể, nhưng nó chắc chắn trả lời một cách hiệu quả . Tôi đang thiếu gì ở đây?
aliteralmind

2
Một số ví dụ thực sự tốt ở đây, và mã nhận xét độc đáo. Một sự trợ giúp tuyệt vời cho những người đến với trang này.
chim

9

Bí danh Bash hoàn toàn không chấp nhận tham số. Tôi vừa thêm một bí danh để tạo một ứng dụng phản ứng mới chấp nhận tên ứng dụng làm tham số. Đây là quá trình của tôi:

Mở bash_profile để chỉnh sửa trong nano

nano /.bash_profile

Thêm bí danh của bạn, một cho mỗi dòng:

alias gita='git add .'
alias gitc='git commit -m "$@"'
alias gitpom='git push origin master'
alias creact='npx create-react-app "$@"'

lưu ý: "$ @" chấp nhận các tham số được truyền vào như "creact my-new-app"

Lưu và thoát trình chỉnh sửa nano

ctrl + o để viết (nhấn enter); ctrl + x để thoát

Yêu cầu thiết bị đầu cuối sử dụng các bí danh mới trong .bash_profile

source /.bash_profile

Đó là nó! Bây giờ bạn có thể sử dụng bí danh mới của mình


6

Lưu ý: Trong trường hợp ý tưởng không rõ ràng, thì nên sử dụng bí danh cho bất cứ thứ gì trừ bí danh, cái đầu tiên là 'hàm trong bí danh' và thứ hai là 'khó đọc chuyển hướng / nguồn'. Ngoài ra, có những sai sót (mà tôi nghĩ sẽ rõ ràng, nhưng chỉ trong trường hợp bạn bối rối: Tôi không có nghĩa là chúng thực sự được sử dụng ... bất cứ nơi nào!)

.................................................. .................................................. ............................................

Tôi đã trả lời điều này trước đây và nó luôn như thế này trong quá khứ:

alias foo='__foo() { unset -f $0; echo "arg1 for foo=$1"; }; __foo()'

đó là tốt và tốt, trừ khi bạn đang tránh sử dụng tất cả các chức năng cùng nhau. trong trường hợp đó bạn có thể tận dụng khả năng to lớn của bash để chuyển hướng văn bản:

alias bar='cat <<< '\''echo arg1 for bar=$1'\'' | source /dev/stdin'

Cả hai đều có cùng độ dài cho hoặc lấy một vài ký tự.

Các kicker thực sự là sự khác biệt thời gian, trên cùng là 'phương thức chức năng' và dưới cùng là phương pháp 'nguồn chuyển hướng'. Để chứng minh lý thuyết này, thời gian nói lên chính nó:

arg1 for foo=FOOVALUE
 real 0m0.011s user 0m0.004s sys 0m0.008s  # <--time spent in foo
 real 0m0.000s user 0m0.000s sys 0m0.000s  # <--time spent in bar
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.010s user 0m0.004s sys 0m0.004s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.011s user 0m0.000s sys 0m0.012s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.012s user 0m0.004s sys 0m0.004s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.010s user 0m0.008s sys 0m0.004s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE

Đây là phần dưới cùng của khoảng 200 kết quả, được thực hiện trong khoảng thời gian ngẫu nhiên. Có vẻ như việc tạo / hủy chức năng mất nhiều thời gian hơn chuyển hướng. Hy vọng rằng điều này sẽ giúp khách truy cập trong tương lai cho câu hỏi này (không muốn giữ nó cho riêng tôi).


2
Có một bí danh xác định một chức năng, sau đó chạy chức năng đó chỉ là ngớ ngẩn. Chỉ cần viết một chức năng. Đối với hầu hết mọi mục đích, bí danh được thay thế bởi các hàm shell.
geirha

trong trường hợp bạn không đọc toàn bộ những gì bạn có thể thử, tôi đã minh họa tại sao việc sử dụng phương thức hàm không tốt như lúc đầu, và hơn nữa, nó không hề ngớ ngẩn chút nào. Dừng đăng và hạ cấp chỉ vì cá nhân bạn không thích nó ... hoặc ít nhất là đưa ra một lời giải thích hợp lệ. Gọi tên là dấu hiệu đầu tiên gần gũi ...
osirisgothra

1
Cái thứ hai (bí danh thanh) có một số tác dụng phụ. Đầu tiên, lệnh không thể sử dụng stdin. Thứ hai, nếu không có đối số nào được cung cấp sau bí danh, thì bất kỳ đối số nào mà shell sẽ xảy ra đều được chuyển qua. Sử dụng một chức năng tránh tất cả các tác dụng phụ. (Cũng vô dụng sử dụng mèo).
geirha

2
hey tôi không bao giờ nói rằng đó là ý tưởng tốt để làm bất cứ điều gì trong số này, tôi chỉ nói rằng còn có nhiều cách khác để thực hiện - ý tưởng chính ở đây là bạn không nên sử dụng các hàm trong bí danh vì chúng chậm hơn thậm chí phức tạp chuyển hướng, tôi nghĩ rằng điều đó là hiển nhiên nhưng tôi đoán tôi phải đánh vần nó cho mọi người (điều mà tôi cũng bị mắng vì bài viết quá phồng nếu tôi làm điều đó ngay từ đầu)
osirisgothra

1
Vì thời gian của thanh là 0, nên tôi nghi ngờ rằng vỏ không đúng thời gian này. Lưu ý rằng thông báo thời gian được in trước khi lệnh được chạy? Ergo, nó không có gì và sau đó thực hiện thanh, vì vậy bạn hoàn toàn không đo thanh. Làm điều gì đó phức tạp hơn, hoặc một vòng lặp lớn tại quán bar để bạn có thể làm cho nó rõ ràng hơn mà bạn đang thời gian không có gì
Evan Langlois

6

Nếu bạn đang tìm kiếm một cách chung để áp dụng tất cả các thông số cho một hàm, không chỉ một hoặc hai hoặc một số lượng mã hóa cứng khác, bạn có thể làm theo cách này:

#!/usr/bin/env bash

# you would want to `source` this file, maybe in your .bash_profile?
function runjar_fn(){
    java -jar myjar.jar "$@";
}

alias runjar=runjar_fn;

Vì vậy, trong ví dụ trên, tôi chuyển tất cả các tham số từ khi tôi chạy runjarđến bí danh.

Ví dụ, nếu tôi đã làm runjar hi therenó sẽ thực sự chạy java -jar myjar.jar hi there. Nếu tôi đã làm runjar one two threenó sẽ chạy java -jar myjar.jar one two three.

Tôi thích $@giải pháp dựa trên này vì nó hoạt động với bất kỳ số lượng params nào.


4
Tại sao không chỉ đặt tên hàm runjarthay vì đặt bí danh cho hàm? Có vẻ phức tạp không cần thiết!
Evan Langlois

Các hàm @EvanLanglois được tự động alias-ed (hoặc có các thuộc tính của những thứ được truyền vào alias) trong các tệp bash? nếu có, thì đó chỉ là tôi không biết điều đó
Micah

Đừng hiểu ý của bạn. Bí danh là một tên khác, có thể là một người hoặc một chức năng. Vì vậy, bạn đã thực hiện một chức năng, sau đó bạn đã tạo một tên thứ hai cho chức năng. Không có gì đặc biệt về bí danh, nó chỉ là một tên thứ hai và không bắt buộc. Những gì bạn nhập vào dòng lệnh có thể là các hàm bên trong hoặc bên ngoài, vì vậy "hàm" tạo một lệnh mới, không phải bí danh.
Evan Langlois

4
Điều này là vô nghĩa. Nó giống như alias runjar='java -jar myjar.jar'. Bí danh không chấp nhận đối số, nhưng chỉ ở cuối.
Tom Hale

6

Trân trọng với tất cả những người nói rằng bạn không thể chèn một tham số vào giữa bí danh mà tôi vừa kiểm tra và thấy rằng nó đã hoạt động.

bí danh mycommand = "python3" $ 1 "script.py --folderoutput KẾT QUẢ /"

Khi tôi chạy mycommand foobar, nó hoạt động chính xác như thể tôi đã gõ lệnh từ lâu.


Hoàn toàn có thể, bí danh có thể nhận được các tham số, tôi đang sử dụng cái này, ví dụ: alias commit = "git commit -m $ 1"
agapitocandemor

Không làm việc cho tôi: alias myalias="echo 1 "$1" 3"; myalias 2cho tôi:1 3 2
dirdi

4

Có những lý do kỹ thuật hợp pháp để muốn một giải pháp tổng quát cho vấn đề bí danh bash không có cơ chế để đưa ra một lập luận tùy ý định vị lại. Một lý do là nếu lệnh bạn muốn thực thi sẽ bị ảnh hưởng bất lợi bởi những thay đổi đối với môi trường do thực thi một chức năng. Trong tất cả các trường hợp khác , các chức năng nên được sử dụng.

Điều gần đây buộc tôi phải thử một giải pháp cho vấn đề này là tôi muốn tạo ra một số lệnh viết tắt để in các định nghĩa về biến và hàm. Vì vậy, tôi đã viết một số chức năng cho mục đích đó. Tuy nhiên, có một số biến nhất định (hoặc có thể) được thay đổi bởi chính hàm gọi. Trong số đó là:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

Lệnh cơ bản mà tôi đã sử dụng (trong một hàm) để in defns biến. ở dạng đầu ra của lệnh set là:

sv () { set | grep --color=never -- "^$1=.*"; }

Ví dụ:

> V=voodoo
sv V
V=voodoo

Vấn đề: Điều này sẽ không in định nghĩa của các biến được đề cập ở trên vì chúng nằm trong ngữ cảnh hiện tại , ví dụ: nếu trong dấu nhắc trình bao tương tác (hoặc không có trong bất kỳ lệnh gọi hàm nào), FUNCNAME không được xác định. Nhưng chức năng của tôi cho tôi biết thông tin sai:

> sv FUNCNAME
FUNCNAME=([0]="sv")

Một giải pháp tôi đã đưa ra đã được đề cập bởi những người khác trong các bài viết khác về chủ đề này. Đối với lệnh cụ thể này để in biến defns., Và chỉ yêu cầu một đối số, tôi đã làm điều này:

alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'

Cung cấp đầu ra chính xác (không có) và trạng thái kết quả (sai):

> asv FUNCNAME
> echo $?
1

Tuy nhiên, tôi vẫn cảm thấy bắt buộc phải tìm một giải pháp phù hợp với số lượng đối số tùy ý.

Một giải pháp chung để vượt qua các lý lẽ tùy tiện cho một lệnh bí danh Bash:

# (I put this code in a file "alias-arg.sh"):

# cmd [arg1 ...] – an experimental command that optionally takes args,
# which are printed as "cmd(arg1 ...)"
#
# Also sets global variable "CMD_DONE" to "true".
#
cmd () { echo "cmd($@)"; declare -g CMD_DONE=true; }

# Now set up an alias "ac2" that passes to cmd two arguments placed
# after the alias, but passes them to cmd with their order reversed:
#
# ac2 cmd_arg2 cmd_arg1 – calls "cmd" as: "cmd cmd_arg1 cmd_arg2"
#
alias ac2='
    # Set up cmd to be execed after f() finishes:
    #
    trap '\''cmd "${CMD_ARGV[1]}" "${CMD_ARGV[0]}"'\'' SIGUSR1;
    #        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    #       (^This is the actually execed command^)
    #
    # f [arg0 arg1 ...] – acquires args and sets up trap to run cmd:
    f () {
        declare -ag CMD_ARGV=("$@");  # array to give args to cmd
        kill -SIGUSR1 $$;             # this causes cmd to be run
        trap SIGUSR1;                 # unset the trap for SIGUSR1
        unset CMD_ARGV;               # clean up env...
        unset f;                      # incl. this function!
    };
    f'  # Finally, exec f, which will receive the args following "ac2".

Ví dụ:

> . alias-arg.sh
> ac2 one two
cmd(two one)
>
> # Check to see that command run via trap affects this environment:
> asv CMD_DONE
CMD_DONE=true

Một điều thú vị về giải pháp này là tất cả các thủ thuật đặc biệt được sử dụng để xử lý các tham số vị trí (đối số) cho các lệnh sẽ hoạt động khi soạn thảo lệnh bị bẫy. Sự khác biệt duy nhất là cú pháp mảng phải được sử dụng.

Ví dụ,

Nếu bạn muốn "$ @", hãy sử dụng "$ {CMD_ARGV [@]}".

Nếu bạn muốn "$ #", hãy sử dụng "$ {# CMD_ARGV [@]}".

Vân vân.


3

Khi tôi đã làm một số dự án thú vị và tôi vẫn sử dụng nó. Nó hiển thị một số hình ảnh động trong khi tôi sao chép các tập tin thông qua cplệnh vì cpnó không hiển thị bất cứ điều gì và nó gây khó chịu. Vì vậy, tôi đã thực hiện bí danh này

alias cp="~/SCR/spiner cp"

Và đây là kịch bản spiner

#!/bin/bash

#Set timer
T=$(date +%s)

#Add some color
. ~/SCR/color

#Animation sprites
sprite=( "(* )  ( *)" " (* )( *) " " ( *)(* ) " "( *)  (* )" "(* )  ( *)" )

#Print empty line and hide cursor
printf "\n${COF}"

#Exit function
function bye { printf "${CON}"; [ -e /proc/$pid ] && kill -9 $pid; exit; }; trap bye INT

#Run our command and get its pid
"$@" & pid=$!

#Waiting animation
i=0; while [ -e /proc/$pid ]; do sleep 0.1

    printf "\r${GRN}Please wait... ${YLW}${sprite[$i]}${DEF}"
    ((i++)); [[ $i = ${#sprite[@]} ]] && i=0

done

#Print time and exit
T=$(($(date +%s)-$T))
printf "\n\nTime taken: $(date -u -d @${T} +'%T')\n"

bye

Nó trông như thế này

nhập mô tả hình ảnh ở đây

Hoạt hình chu kỳ)

nhập mô tả hình ảnh ở đây


2

Để lấy tham số, bạn nên sử dụng các hàm!

Tuy nhiên, $ @ được giải thích khi tạo bí danh thay vì trong quá trình thực thi bí danh và thoát $ cũng không hoạt động. Làm thế nào để tôi giải quyết vấn đề này?

Bạn cần sử dụng hàm shell thay vì bí danh để thoát khỏi vấn đề này. Bạn có thể định nghĩa foo như sau:

function foo() { /path/to/command "$@" ;}

HOẶC LÀ

foo() { /path/to/command "$@" ;}

Cuối cùng, gọi foo () của bạn bằng cú pháp sau:

foo arg1 arg2 argN

Hãy chắc chắn rằng bạn thêm foo () vào ~/.bash_profilehoặc ~/.zshrctệp.

Trong trường hợp của bạn, điều này sẽ làm việc

function trash() { mv $@ ~/.Trash; }

Tôi không hiểu ý của bạn Tôi nghĩ rằng nó không quan trọng khi các đối số được giải thích. Cuối cùng, Aliase chấp nhận nhiều tham số như bạn muốn.
Timo

Nhưng tốt hơn là làm điều đó với các chức năng. Bí danh không có nghĩa là cho điều đó.
Ahmad Awais

1

Các hàm thực sự hầu như luôn luôn là câu trả lời như đã được đóng góp và xác nhận bởi trích dẫn này từ trang người đàn ông: "Đối với hầu hết mọi mục đích, bí danh được thay thế bởi các hàm shell."

Để đầy đủ và vì điều này có thể hữu ích (cú pháp nhẹ hơn một chút), có thể lưu ý rằng khi (các) tham số tuân theo bí danh, chúng vẫn có thể được sử dụng (mặc dù điều này sẽ không giải quyết được yêu cầu của OP). Đây có lẽ là dễ dàng nhất để chứng minh với một ví dụ:

alias ssh_disc='ssh -O stop'

cho phép tôi gõ smth like ssh_disc myhost, được mở rộng như mong đợi:ssh -O stop myhost

Điều này có thể hữu ích cho các lệnh có các đối số phức tạp (bộ nhớ của tôi không còn là thứ nó sử dụng nữa ...)


1

Cả hai hàm và bí danh đều có thể sử dụng các tham số như các hàm khác đã hiển thị ở đây. Ngoài ra, tôi muốn chỉ ra một vài khía cạnh khác:

1. chức năng chạy trong phạm vi riêng của nó, phạm vi chia sẻ bí danh

Có thể hữu ích khi biết sự khác biệt này trong trường hợp bạn cần che giấu hoặc phơi bày một cái gì đó. Nó cũng gợi ý rằng một hàm là sự lựa chọn tốt hơn cho việc đóng gói.

function tfunc(){
    GlobalFromFunc="Global From Func" # Function set global variable by default
    local FromFunc="onetwothree from func" # Set a local variable

}

alias talias='local LocalFromAlias="Local from Alias";  GlobalFromAlias="Global From Alias" # Cant hide a variable with local here '
# Test variables set by tfunc
tfunc # call tfunc
echo $GlobalFromFunc # This is visible
echo $LocalFromFunc # This is not visible
# Test variables set by talias
# call talias
talias
echo $GlobalFromAlias # This is invisible
echo $LocalFromAlias # This variable is unset and unusable 

Đầu ra:

bash-3.2$     # Test variables set by tfunc
bash-3.2$     tfunc # call tfunc
bash-3.2$     echo $GlobalFromFunc # This is visible
Global From Func
bash-3.2$     echo $LocalFromFunc # This is not visible

bash-3.2$     # Test variables set by talias
bash-3.2$     # call talias
bash-3.2$     talias
bash: local: can only be used in a function
bash-3.2$     echo $GlobalFromAlias # This is invisible
Global From Alias
bash-3.2$ echo $LocalFromAlias # This variable is unset and unusable

2. tập lệnh bao bọc là một lựa chọn tốt hơn

Nó đã xảy ra với tôi nhiều lần rằng không thể tìm thấy bí danh hoặc chức năng khi đăng nhập thông quassh hoặc liên quan đến việc chuyển đổi tên người dùng hoặc môi trường nhiều người dùng. Có một số mẹo và thủ thuật với việc tìm nguồn cung cấp các tệp chấm hoặc điều thú vị này với bí danh: hãy alias sd='sudo 'để bí danh tiếp theo này alias install='sd apt-get install'hoạt động như mong đợi (chú ý thêm không gian trong sd='sudo '). Tuy nhiên, một tập lệnh bao bọc hoạt động tốt hơn một hàm hoặc bí danh trong các trường hợp như thế này. Ưu điểm chính với tập lệnh trình bao bọc là nó có thể nhìn thấy / thực thi được theo đường dẫn dự định (ví dụ / usr / loca / bin /) trong đó như một hàm / bí danh cần phải có nguồn gốc trước khi có thể sử dụng được. Ví dụ: bạn đặt một hàm trong ~ / .bash_profile hoặc ~ / .bashrc cho bash, nhưng sau đó chuyển sang shell khác (nghĩa làzsh) sau đó chức năng không hiển thị nữa. Vì vậy, khi bạn nghi ngờ, một tập lệnh bao bọc luôn là giải pháp đáng tin cậy và di động nhất.


1
Tại sao bạn nghĩ phiên bản chức năng không hoạt động?
tripleee

@tripleee. Tôi đã chỉnh sửa bài viết để dễ đọc hơn. Trong tiêu đề "1. bí danh hoạt động, chức năng ..." Tôi đã minh họa tại sao một phiên bản chức năng không hoạt động. Và có lẽ để trả lời trực tiếp câu hỏi, hàm giới thiệu một phạm vi mới mà bí danh không có.
biocyberman

Bạn nói nó không hoạt động nhưng tôi không tin bạn. sourcetrong một chức năng hoạt động tốt
tripleee

1
f () { source /tmp/nst; }làm chính xác những gì tôi mong đợi. Có thể bạn PATHsai nên nó chạy sai activatehoặc cái gì đó; nhưng chạy sourcetừ một chức năng hoạt động tốt.
tripleee

1
BTW, re: sử dụng functiontừ khóa trong định nghĩa của bạn, xem wiki.bash-hackers.org/scripting/obsolete - function funcname {là bash cú pháp ksh cổ đại hỗ trợ cho khả năng tương thích ngược với trình bao tiền POSIX, trong khi đó funcname() {là cú pháp chuẩn hóa POSIX chính thức. function funcname() {là sự không phù hợp của cả hai không tương thích với ksh cổ đại hoặc tương thích với POSIX sh, và do đó tốt nhất nên tránh.
Charles Duffy

1

Đây là ví dụ:

alias gcommit='function _f() { git add -A; git commit -m "$1"; } ; _f'

Rất quan trọng:

  1. Có một không gian sau {và trước }.
  2. Có một ;sau mỗi lệnh theo trình tự. Nếu bạn quên điều này sau lệnh cuối cùng, bạn sẽ thấy >dấu nhắc thay thế!
  3. Đối số được đính kèm trong dấu ngoặc kép là "$1"

2
Không cần tạo bí danh cho hàm, chỉ cần sử dụng hàm trực tiếp.
dùng3439894

1

Như đã được chỉ ra bởi những người khác, sử dụng một chức năng nên được coi là thực hành tốt nhất.

Tuy nhiên, đây là một cách tiếp cận khác, tận dụng xargs:

alias junk="xargs -I "{}" -- mv "{}" "~/.Trash" <<< "

Lưu ý rằng điều này có tác dụng phụ liên quan đến chuyển hướng của luồng.


0

Bạn không phải làm bất cứ điều gì, bí danh sẽ tự động làm điều này.

Ví dụ, nếu tôi muốn làm cho git pull origin master được tham số hóa, tôi có thể chỉ cần tạo một bí danh như sau:

alias gpull = 'git pull origin '

và khi thực sự gọi nó, bạn có thể chuyển 'master' (tên nhánh) làm tham số, như thế này:

gpull master
//or any other branch
gpull mybranch

Điều này không trả lời câu hỏi, vì đối số không thể được đặt tự do, mà chỉ ở cuối.
dirdi
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.