パラメータを取るBashエイリアスを作成しますか?


1273

私は以前CShell()。これにより、パラメータを受け取るエイリアスを作成できます。表記は次のようなものでした

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

Bashでは、これは機能していないようです。Bashには多くの便利な機能があるので、これは実装されていると思いますが、どうしたらいいのでしょうか。



2
引数は引用符で囲むようにしてください"$1"
Christophe Roussy 2016

この質問は、SOには関係ありません。これはUNIX.SE回答されたので、迷惑をかける必要もないという答えが得られました。「たとえば、のエイリアスlsを作成したls -la場合、入力ls foo barするとコマンドラインで実際に実行さls -la foo barれます。」
Dan Dascalescu 2017年

7
これは、変数を文字列の途中に補間するのに役立ちません
Franz Sittampalam 2018

1
これは、私がこの誤りを発見するために使用したlilテストエイリアスですalias test_args="echo PREFIX --$1-- SUFFIX"。これを呼び出すとtest_args ABCD、次のコンソール出力が生成されますPREFIX ---- SUFFIX ABCD
jxramos

回答:


2124

Bashエイリアスはパラメーターを直接受け入れません。関数を作成する必要があります。

aliasパラメータを受け付けませんが、エイリアスのように関数を呼び出すことができます。例えば:

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


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

ちなみに、あなた.bashrcと他のファイルで定義されたBash関数は、シェル内のコマンドとして利用できます。たとえば、次のように以前の関数を呼び出すことができます

$ myfunction original.conf my.conf

48
$1引用符で囲む必要がありますか?
ユルゲンポール

263
エイリアスを宣言する必要すらありません。関数を定義するだけで十分です。
dinigo 2013

207
エイリアスを関数に変更する場合source、.bashrcを実行すると関数が追加されますが、古いエイリアスのエイリアスは解除されません。エイリアスは関数よりも優先されるため、エイリアスを使用しようとします。シェルを閉じて再度開くか、を呼び出す必要がありますunalias <name>。たぶん私は無駄にした5分だけ誰かを救うでしょう。
Marty Neal、2014年

56
@MartinNeal:私がSunで学んだ時間節約のトリックの1つは、単にを実行することexec bashです:新しいシェルを開始し、閉じて再度開いた場合と同じように、構成のクリーンな読み取りを提供しますが、そのセッションの環境変数設定も保持します。また、bashスタックなしのように処理したい場合は、execなしで実行すると便利です。
Macneil Shonle 2014

21
@mich-はい、常にbash変数を引用符で囲みます。例えばmv "$1" "$1.bak"。引用符なしで、$ 1が「hello world」の場合、のmv hello world hello world.bak代わりに実行しますmv "hello world" "hello world.bak"
orion elenzil 2015年

208

上記の答えを絞り込むと、エイリアスの場合と同じように1行の構文を取得できます。これは、シェルファイルまたは.bashrcファイルのアドホック定義に便利です。

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

bash$ myfunction original.conf my.conf

右大括弧を閉じる前のセミコロンを忘れないでください。同様に、実際の質問の場合:

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

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

または:

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

3
入ってくるかもしれない引数の配列を反復することを示しているので、私はこの答えを好みます。$ 1と$ 2は単なる特別なケースであり、これもこの答えに示されています。
フィロヴィヴェロ2014

16
トラブルが発生したときにデータを失わないように変更mv "$1" "$1.bak"; cp "$2" "$1"mv "$1" "$1.bak" && cp "$2" "$1"ますmv(例:ファイルシステムがいっぱい)。
Henk Langeveld

3
「右大括弧の前のセミコロンを忘れないでください。」何度もこれ!ありがとう:)
Kaushal Modi 2018

また、最初のブラケットの後と最後のブラケットの前のスペースも必要です。
ブライアンチャペル

1
@HenkLangeveld発言が完全に正しい間、それはあなたがしばらくの間いたことを示しています-「デバイスにスペースが残っていません」というエラーが最後に発生したのはいつだったかわかりません;-)。(キッチンカウンターのスペースがなくなったので、定期的に使っています!)最近はあまりないようです。
ピーター-モニカを

124

質問は単に間違って尋ねられます。aliasすでに存在するものに2番目の名前を追加するだけなので、パラメーターを受け取るエイリアスを作成しません。OPが必要とする機能はfunction、新しい関数を作成するコマンドです。関数には既に名前が付けられているため、関数にエイリアスを設定する必要はありません。

あなたはこのようなものが欲しいと思います:

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

それでおしまい!$ 1、$ 2、$ 3などのパラメーターを使用するか、すべて$ @で埋め込むことができます


7
この答えはそれをすべて言います。このページの下から読んだら、時間が節約できたでしょう。
joe

-1エイリアスと関数は同等ではありません...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
ファジーロジック

あなたは本当に引用する必要がある$@など、空白を含むファイル名をサポートするために
トム・ヘイル

エイリアスパラメータがなく、代わりに関数を使用することは、一般的な説明であるはずです。与えられた関数は、元の例に対抗するための単なる例でした。私はその人が汎用のゴミ機能を探していたとは思いません。ただし、より優れたコードを提示するために、答えを更新しました。
エヴァンラングロワ2017

1
@FuzzyLogic-私はあなたのコメントのコードを開梱するために数分を費やしました。これは、いくつかのコードをコメントにまとめて適切にフォーマットできないコメントに(多くの)興味深い作業です。私はまだそれが何をしているのか、さらに重要なことには、それがあなたの(正しい)アサーションをサポートする理由を正確に理解していません。
Joe

110

TL; DR:代わりにこれを行う

コマンドの途中に引数を置くエイリアスよりも関数を使用する方がはるかに簡単で読みやすいです。

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

読み進めれば、シェル引数の処理について知っておく必要のないことがわかります。知識は危険です。ダークサイドがあなたの運命を永遠に支配する前に、あなたが望む結果を手に入れてください。

明確化

bashエイリアス引数を受け入れますが、最後のみです:

$ alias speak=echo
$ speak hello world
hello world

引数をコマンドの途中に置くことaliasは確かに可能ですが、醜くなります。

家でこれを試してはいけません、キディ!

制限を回避し、他の人が不可能だと言うことを行うのが好きな場合は、ここにレシピがあります。あなたの髪がぐちゃぐちゃになり、あなたの顔がすすり狂った科学者のスタイルで覆われてしまうなら、私を責めないでください。

回避策はalias、最後にのみ受け入れる引数を、途中に挿入するラッパーに渡し、コマンドを実行することです。

解決策1

関数自体を使用することに本当に反対の場合は、以下を使用できます。

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

あなたは置き換えることができます$@$1、あなたが最初の引数だけをしたい場合。

説明1

これによりf、引数が渡される一時関数が作成されます(これはf最後に呼び出されることに注意してください)。のunset -fそれがその後の周りにハングアップしないようにエイリアスが実行されると、関数定義を削除します。

解決策2

サブシェルを使用することもできます。

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

説明2

エイリアスは次のようなコマンドを作成します。

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

コメント:

  • プレースホルダー_は必須ですが、何でもかまいません。これは、に設定されますshs「を$0、およびユーザ指定された引数の最初が消費されないように必要とされます。デモンストレーション:

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
  • 単一引用符内の単一引用符は必須です。二重引用符で動作しない例を次に示します。

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

    ここでは、インタラクティブシェルの$0との値が$@二重引用符置き換えられてから、に渡されshます。ここに証明があります:

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

    一重引用符は、これらの変数が対話型シェルによって解釈されないことを保証し、文字通りに渡されsh -cます。

    二重引用符とを使用することもできます\$@が、ベストプラクティスは引数を引用符\"\$@\"で囲むことです(スペースが含まれている可能性があるため)。


2
解決策1のために、必ず単一引用符、および回避を使用して作る\」$の周りに@ A非常に有用な技術あなたがそれを必要とする場合TYを。。。
sgtz

ソリューション1は、私が必要とする各サーバーの引数でrdesktop-vrdpをラップするのに役立ちました。
Hsehdar

最後に引数を受け入れることは、「git checkout {branchname}」を単純な「gc {branchname}」に置き換えるために必要なことです。.bash_profileに追加する必要がありましたalias gc='git checkout'
AbstractVoid

@sgtzなぜ引用符を削除したいの$@ですか?たとえば、スペースが含まれているファイルがある場合に必要です。
トム・ヘイル

@TomHaleこれは多少言語学ですが、誰かが本当に関数の使用に反対している場合(理由が何であれ)ソリューション1はあまり役に立ちません。エイリアス。第2に、「bashエイリアスは引数を受け入れますが、最後にのみ」はよりセマンティクスです。エイリアスは定義ごとに単語を文字列に置き換えたものです。引数を受け入れる必要はありませんが、置換によって実行されるコマンドは可能です。エイリアスは文字の置き換えであり、それ以上でもそれ以下でもありません。番号?
BUFU

39

別の解決策は、最近作成したツールであるマーカーを使用することです。このツールを使用すると、コマンドテンプレートを「ブックマーク」して、コマンドプレースホルダーに簡単にカーソルを置くことができます。

コマンドラインマーカー

ほとんどの場合、シェル関数を使用しているので、頻繁に使用するコマンドをコマンドラインで何度も記述する必要はありません。この使用例で関数を使用する際の問題は、コマンドボキャブラリに新しい用語を追加することと、実際のコマンドでパラメーターが参照する関数を覚えておく必要があることです。マーカーの目標は、その精神的負担を取り除くことです。


14

あなたがしなければならないすべてはエイリアスの中に関数を作ることです:

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

単一引用符は機能しないため、 "$ 1"を二重引用符で囲む必要あります。


5
それは賢いですが、質問でエイリアスを作成するように指定したという事実以外に、最初にエイリアスと同じ名前の関数を作成しない理由はありますか?
-xaxxon、

1
@xaxxonありませんが、関数ではなくエイリアスを使用するのが最も簡単な方法です。
Ken Tran

1
これは動作しません。Ubuntu 18でエラーが発生しますbash: syntax error near unexpected token '{mkdir'
Shital Shah

;関数内の末尾が欠落している可能性が_mkcd最も高いのは、そのエラーです。
Jetchisel

前後にスペースを残す{}
hesham_EE

10

これが私の~/.bashrcにある関数の3つの例です。これらは基本的にパラメーターを受け入れるエイリアスです。

#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
}

参照:


えっ?これは関数であり、エイリアスではありません。そして、あなたの参照の1つは、まさにこの質問です。
3

2
いいえ、機能とまったく同じように機能します。ここでの回答のいくつかが説明するように、パラメーターを取るエイリアスを作成することはできません。あなたができることは、あなたがやったことである関数を書くことです。
Tripleee、2015年

1
@tripleee私のbash初心者の観点から、コメントを読む前に、それはエイリアス(エイリアスを作成する別の方法)だと思いました。私の知る限り、それはまったく同じように機能します。これは、用語を理解していなくても、基本的にパラメーターを受け入れるエイリアスです。問題はありません。この問題における他の回答へのリンクを明確にしました。これを作成するのに役立ちました。
aliteralmind 2015年

1
おそらく、これは「パラメーターを受け入れるbashエイリアス」の質問には特に答えていません。これは不可能だと理解しているためですが、確かに効果的に答えます。ここで何が欠けていますか?
aliteralmind 2015年

2
ここにいくつかの本当に良い例と、よくコメントされたコードがあります。このページにアクセスする人々のための大きな助け。
2015年

9

Bashエイリアスは絶対にパラメーターを受け入れます。エイリアスを追加して、アプリ名をパラメーターとして受け入れる新しい反応アプリを作成しました。これが私のプロセスです:

nanoで編集するためにbash_profileを開きます

nano /.bash_profile

1行に1つずつエイリアスを追加します。

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

注:「$ @」は、「creact my-new-app」のように渡されるパラメーターを受け入れます

nanoエディターを保存して終了する

Ctrl + Oで書き込み(Enterキーを押す)。ctrl + xで終了

.bash_profileの新しいエイリアスを使用するように端末に指示する

source /.bash_profile

それでおしまい!これで新しいエイリアスを使用できます


6

注意:アイデアが明確でない場合は、エイリアス以外のエイリアスを使用することはお勧めできません。最初のエイリアスは「エイリアス内の関数」で、2番目のエイリアスは「読みにくいリダイレクト/ソース」です。また、欠点もあります(これは明らかだと思いますが、混乱する場合に備えて:実際に使用されることを意味するわけではありません...どこでも!)

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

私は以前にこれに答えたことがあり、それは過去に常にこのようなものでした:

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

関数をすべて一緒に使用することを避けない限り、これは問題なく優れています。その場合、テキストをリダイレクトするbashの膨大な機能を利用できます。

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

どちらもほぼ同じ長さで、数文字を指定または取得します。

本当のキッカーは、時間差、「関数法」と「リダイレクト・ソース」方式である底部であるトップです。この理論を証明するために、タイミングがそれ自体を物語っています。

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

これは、ランダムな間隔で行われる約200件の結果の下部です。関数の作成/破棄には、リダイレクトよりも時間がかかるようです。うまくいけば、これがこの質問への将来の訪問者を助けるでしょう(私自身にそれを保ちたくありませんでした)。


2
関数を定義するエイリアスを持っていて、その関数を実行するのはばかげています。関数を書くだけです。ほとんどすべての目的で、エイリアスはシェル関数に取って代わられました。
geirha

あなたがすべてを読んでいないかもしれない場合に備えて、私は関数メソッドの使用がそもそもそれほど良くない理由を説明していました、さらに、それはまったく愚かではありません。個人的に気に入らなかったという理由だけで投稿や投票を停止するか、少なくとも有効な説明を行ってください。名前の呼び出しは最初の兆候である心の緊密さ...
osirisgothra '20

1
2番目(バーのエイリアス)にはいくつかの副作用があります。まず、コマンドはstdinを使用できません。次に、エイリアスの後に引数が指定されていない場合、シェルがたまたま引数を渡してしまいます。関数を使用すると、これらすべての副作用を回避できます。(猫の無駄使いも)。
geirha

2
これを実行するのは良いアイデアだと言ったことはありませんが、他の方法もあると言っただけです。ここでの主なアイデアは、複雑な関数よりも関数が遅いため、エイリアスで関数を使用しないことです。リダイレクト、それは明白だったと思いましたが、私はそれをすべての人に綴る必要があると思います(私が最初にそうした場合、投稿が肥大化しすぎると怒鳴られます)
osirisgothra

1
barのタイミングはすべて0なので、シェルがこれを正しくタイミングしていないのではないかと思います。コマンドが実行される前に時間メッセージが出力されることに注意してください。エルゴ、何も時間を計らず、それからバーを実行するので、あなたは全くバーを測定していません。もっと複雑なこと、または大きなループを実行して、タイミング
Evan Langlois

6

1つまたは2つまたは他のハードコードされた量だけでなく、すべてのパラメーターを関数に適用する一般的な方法を探している場合は、次の方法で行うことができます。

#!/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;

上の例では、実行時runjarにエイリアスにすべてのパラメーターを渡します。

たとえば、私がrunjar hi there実行した場合、実際に実行されることになりますjava -jar myjar.jar hi there。私がやっrunjar one two threeた場合、それは実行されjava -jar myjar.jar one two threeます。

これは好きです$@-任意の数のパラメーターで動作するため、ベースのソリューションです。


4
関数runjarのエイリアスにするのではなく、単に関数に名前を付けないのはなぜですか?不必要に複雑に思える!
Evan Langlois

@EvanLanglois関数は、bashファイルで自動的にalias-ed(またはに渡されるもののプロパティalias)されていますか?はいの場合、それは私の知らないことです
ミカ

意味がわからない。エイリアスは、人であれ機能であれ、別の名前です。つまり、関数を作成してから、その関数の別名を作成しました。エイリアスについて特別なことは何もありません。別名だけで、必須ではありません。コマンドラインで入力するのは内部関数でも外部関数でもかまいません。したがって、「関数」はエイリアスではなく新しいコマンドを作成します。
Evan Langlois、2016年

4
これは無意味です。と同じalias runjar='java -jar myjar.jar'です。エイリアスは引数を受け入れますが、最後のみです。
トム・ヘイル

6

エイリアスの途中にパラメータを挿入することができないと言うすべての人に敬意を表して、私はそれをテストしたところ、うまくいったことがわかりました。

エイリアスmycommand = "python3" $ 1 "script.py --folderoutput RESULTS /"

その後、コマンドfoobarを実行すると、コマンドをロングハンドで入力した場合とまったく同じように機能しました。


絶対に、エイリアスはパラメータを取得できます。これを使用している年齢です。例:alias commit = "git commit -m $ 1"
agapitocandemor

私にalias myalias="echo 1 "$1" 3"; myalias 21 3 2
役に立た

4

任意の引数の位置を変更するメカニズムを持たないbashエイリアスの問題に対する一般化されたソリューションが必要となる正当な技術的理由があります。1つの理由は、実行したいコマンドが、関数の実行に起因する環境の変更によって悪影響を受ける場合です。それ以外の場合はすべて、関数を使用する必要があります。

最近これを解決するように強いられたのは、変数と関数の定義を出力するためのいくつかの省略されたコマンドを作成したかったということです。そこで、そのための関数をいくつか作成しました。ただし、関数呼び出し自体によって変更される(または変更される可能性がある)特定の変数があります。それらの中には:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

変数の定義を出力するために(関数で)使用していた基本的なコマンド。setコマンドの出力形式は次のとおりです。

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

例えば:

> V=voodoo
sv V
V=voodoo

問題:上記の変数の定義は現在のコンテキストにあるため、これは出力されません。たとえば、対話型シェルプロンプト(または関数呼び出しではない)の場合、FUNCNAMEは定義されません。しかし、私の関数は間違った情報を教えてくれます:

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

私が思いついた解決策の1つは、このトピックの他の投稿で他の人から言及されています。この特定のコマンドが変数の定義を出力するために、1つの引数しか必要としないため、これを行いました。

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

正しい出力(なし)と結果のステータス(false)を示します。

> asv FUNCNAME
> echo $?
1

しかし、私は依然として、任意の数の引数に対して機能する解決策を見つけることを余儀なくされました。

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".

例えば:

> . 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

このソリューションの良い点は、トラップされたコマンドを作成するときに、コマンドの位置パラメータ(引数)を処理するために使用されるすべての特別なトリックが機能することです。唯一の違いは、配列構文を使用する必要があることです。

例えば、

「$ @」が必要な場合は、「$ {CMD_ARGV [@]}」を使用します。

「$#」が必要な場合は、「$ {#CMD_ARGV [@]}」を使用します。

等。


3

楽しいプロジェクトをやったら、それを使っています。cpコマンドcozを使用してファイルをコピーしているときにアニメーションがcp表示されますが、何も表示されず、イライラします。だから私はこのエイリアスを作りました

alias cp="~/SCR/spiner cp"

そして、これはスピナースクリプトです

#!/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

こんな感じ

ここに画像の説明を入力してください

循環アニメーション)

ここに画像の説明を入力してください


2

パラメータを取るには、関数を使用する必要があります!

ただし、$ @は、エイリアスの実行時ではなくエイリアスの作成時に解釈され、$のエスケープも機能しません。この問題を解決するにはどうすればよいですか?

この問題を取り除くには、エイリアスの代わりにシェル関数を使用する必要があります。次のようにfooを定義できます。

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

または

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

最後に、次の構文を使用してfoo()を呼び出します。

foo arg1 arg2 argN

foo()をファイル~/.bash_profileまたは~/.zshrcファイルに追加してください。

あなたの場合、これはうまくいきます

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

私はあなたの考えを理解していません。議論がいつ解釈されるかは重要ではないと思います。エイリアスは、最後に必要なだけパラメータを受け入れます。
Timo

しかし、関数でそれを行う方が良いです。エイリアスはそのためのものではありません。
Ahmad Awais 2017年

1

実際、関数はほぼ常に答えです。すでに十分に貢献されており、manページのこの引用によって確認されています。「ほとんどすべての目的で、エイリアスはシェル関数に置き換えられています。」

完全を期すため、これは便利な場合があるため(わずかに軽量な構文)、パラメータがエイリアスに従う場合でも、それらを使用できます(ただし、これはOPの要件に対応しません)。これは、例を示すのがおそらく最も簡単です。

alias ssh_disc='ssh -O stop'

のようにsmthと入力するとssh_disc myhost、期待どおりに展開されます。ssh -O stop myhost

これは、複雑な引数をとるコマンドに役立ちます(私のメモリはもう使用されていません...)


1

他のユーザーがここで示したように、関数とエイリアスの両方でパラメーターを使用できます。さらに、私は他のいくつかの側面を指摘したいと思います:

1.関数は独自のスコープで実行され、エイリアスはスコープを共有します

何かを隠したり公開したりする必要がある場合は、この違いを知っておくと便利です。また、関数はカプセル化に適していることも示唆しています。

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 

出力:

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.ラッパースクリプトの方が適しています

ユーザー名やマルチユーザー環境を介してログインしsshたり、ユーザー名やマルチユーザー環境を切り替えたりするときに、エイリアスや関数が見つからないことが何度かありました。ドットファイルのソースに関するヒントやコツ、またはエイリアスを持つ興味深いものがありalias sd='sudo 'ます。この後続のエイリアスalias install='sd apt-get install'を期待どおりに機能させます(の余分なスペースに注意してくださいsd='sudo ')。ただし、このような場合、ラッパースクリプトは関数やエイリアスよりもうまく機能します。ラッパースクリプトの主な利点は、意図したパス(つまり、/ usr / loca / bin /)の下で可視/実行可能であり、関数/エイリアスを使用する前にソースにする必要があることです。たとえば、〜/ .bash_profileまたは〜/ .bashrcに関数を配置し、bash後で別のシェルに切り替える(つまりzsh)その後、関数は表示されなくなります。したがって、疑問がある場合は、ラッパースクリプトが常に最も信頼性が高く、移植可能なソリューションです。


1
関数バージョンが機能しないのはなぜですか?
Tripleee

@tripleee。投稿を読みやすくするために編集しました。「1.エイリアスは機能します...」という見出しの下で、関数バージョンが機能しない理由を説明しました。そして多分質問に直接答えるために、関数はエイリアスがしない新しいスコープを導入します。
biocyberman

あなたはそれがうまくいかないと言いますが、私はあなたを信じていません。source関数内でうまく機能します。
tripleee

1
f () { source /tmp/nst; }私が期待することを正確に行います。多分あなたPATHは間違っているので、それは間違っているactivateか何かを実行しています。しかしsource、関数からの実行はうまくいきます。
tripleee

1
ところで、re:functionキーワードを定義で使用します。wiki.bash - hackers.org/ scripting / obsoleteを参照してください-POSIXfunction funcname {シェルとの後方互換性のためにbashがサポートしているのfuncname() {は、公式のPOSIX標準化された構文です。function funcname() {古代のkshと互換性がない、または POSIX shと互換性がない2つのミスマッシュです。
Charles Duffy

1

次に例を示します。

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

非常に重要:

  1. {前後にスペースがあり}ます。
  2. ある;シーケンス内の各コマンドの後。最後のコマンドの後にこれを忘れると、>代わりにプロンプ​​トが表示されます!
  3. 引数は引用符で囲まれています "$1"

2
関数のエイリアスを作成する必要はありません。関数を直接使用するだけです。
user3439894

1

他の人がすでに指摘しているように、関数の使用はベストプラクティスと見なされます。

ただし、これは次の方法を利用したものxargsです。

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

これには、ストリームのリダイレクトに関して副作用があることに注意してください。


0

何もする必要はありません。エイリアスはこれを自動的に行います。

たとえば、git pull origin masterをパラメーター化する場合は、次のようにしてエイリアスを作成できます。

alias gpull = 'git pull origin '

そして実際にそれを呼び出すとき、次のように 'master'(ブランチ名)をパラメーターとして渡すことができます。

gpull master
//or any other branch
gpull mybranch

議論は自由にではなく、最後にのみ置くことができるので、これは質問に答えません。
dirdi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.