独自の「シェルコマンド」(mkdir / cdコンボなど)を作成するにはどうすればよいですか?


41

ディレクトリの作成とそのディレクトリへの移動の両方を行うコマンドを何回希望したかわかりません。基本的には、次のものと同等のものが欲しい:

mkdir -p /arbitrarily/long/path; cd /arbitrarily/long/path

しかし、/arbitrarily/long/path一度だけ入力するだけで、次のようになります:

mk-cd /arbitrarily/long/path

これを行うスクリプトを作成しようとしましたが、スクリプト内のディレクトリのみが変更されます。シェルのディレクトリも変更したいのですが。

#!/bin/bash
mkdir $1
cd $1
export PWD=$PWD

この作業をどのように行うことができますか?


12
ではcd、最初から特別なケースを選択しました。:D
ダニエルB

2
ない、まさに私が探していますが、スーパークールだっcd関連の情報(使用前のディレクトリに戻るcd -、使用をpushdし、popdディレクトリの「スタック」を維持するために):superuser.com/questions/324512/...
クリストファー・ボトムス

8
を入力してmkdir -p /very/long/pathからcd、スペースを使用し、Alt + .を押して最後の引数、つまりディレクトリ名を繰り返すことができます。
チョロバ

2
答えではなく、@ chorobaに似たコメント:を使用することもできますmkdir -p /very/long/path; cd !#:2。文字列!#:2は引数nrに展開されます。2(つまり、/very/long/pathカウントがゼロから始まる3番目の引数)。
インゴブレシュミット

3
@IngoBlechschmidtは、最後のコマンドの最後の引数であるため、さらに簡単に使用できます!$。私は常にこの特定のトリックを使用しますが、履歴拡張でできることはもっとたくさんあります
ワイルドカード

回答:


92

最も簡単な方法は、シェル関数を使用することです:

mkcd() {
    mkdir -p -- "$1" && cd -- "$1"
}

.bashrc別のシェルコマンドのように、ファイルに配置して使用できるようにします。

外部スクリプトとして機能しない理由cdは、実行中のスクリプトの現在のディレクトリを変更しますが、呼び出し元のディレクトリには影響しません。これは仕様です!各プロセスには、子によって継承される独自の作業ディレクトリがありますが、その逆は不可能です。

パイプラインの一部がバックグラウンドで実行されているか、明示的にサブシェルで実行されていない限り、シェル関数はコマンドがソースされた場合と同じように、別のプロセスではなく同じプロセスで実行されます。現在のディレクトリシェルは、関数によって変更できます。

ここで&&使用される両方のコマンドを分離するために使用されるのは、最初のコマンドが成功した場合(mkdir)、2番目のコマンドを実行する()を意味しますcd。そのため、mkdir要求されたディレクトリの作成に失敗した場合、そのディレクトリに移動しようとしても意味がありません。エラーメッセージが表示されmkdir、それだけです。

-p使用されるオプションは、mkdirこのユーティリティに、引数として渡されたディレクトリ名のフルパスの一部である欠落ディレクトリを作成するように指示するためにあります。副作用の1つとして、既存のディレクトリを作成するように要求した場合、mkcd関数は失敗せず、そのディレクトリに移動します。これは問題または機能と見なされる場合があります。前者の場合、たとえばユーザーに警告するだけの方法で関数を変更できます。

mkcd() {
    if [ -d "$1" ]; then
        printf "mkcd: warning, \"%s\" already exists\n" "$1"
    else
        mkdir -p "$1" 
    fi && cd "$1"
}

-pオプションがなければ、初期関数の動作は非常に異なっていたでしょう。

作成するディレクトリを含むディレクトリがまだ存在しない場合はmkdir失敗し、関数も失敗します。

作成するディレクトリが既に存在する場合、mkdir失敗し、cd呼び出されません。

最後に、設定/エクスポートPWDは無意味であることに注意してください。シェルはすでに内部で行っているためです。

編集:--機能の両方のコマンドに、ダッシュで始まるディレクトリ名を許可するオプションを追加しました。


5
また、このコマンドが~/.bashrc他の初期化スクリプトに追加されない限り、このコマンドが永続的に使用可能にならないことも追加する必要があります。
AFH

alias mk-cd 'mkdir -p \!:1; cd \!:1'関数なしでtcshに相当することをbashで行う方法はありませんか?または、拡張エイリアスのようなbash関数を考え始める必要がありますか?
トーマスパドロン-マッカーシー

@ ThomasPadron-McCarthyこのcsh引数渡しメカニズムは、bourne スタイルのエイリアスでは実装されていません。機能は実際に進むべき道であり、はるかに柔軟です。
jlliagre

@ ThomasPadron-McCarthy- エイリアスに渡されたパラメーターにアクセスするためのかなり難解なメカニズムを提供するこの回答をご覧くださいbar。別のオプションは、のように使用することhistory 1ですalias mk-cd='args="$(history 1)" && args="${args#*mk-cd\ }" && mkdir -p "$args" && cd'-これは質問者の例ではうまく機能しますが、同じ行の他のコマンド(たとえば、出力のパイピング)が失敗するため、一般的な解決策ではありません。
AFH

3
@ ThomasPadron-McCarthy制限された機能のようなtcshのエイリアスを考え始める必要があります。
ジル 'SO-悪であるのをやめる'

32

代替ソリューションを追加したいと思います。

スクリプト. or sourceコマンドで呼び出すと機能します。

. mk-cd /arbitrarily/long/path

これを行う場合export、スクリプト内は不要です。.を使用して、入力をバイパスできますalias

alias mk-cd='. mk-cd'

これが機能する理由は、スクリプトが通常サブシェルで実行されるため、完了時に環境が失われるが、.(またはsource)コマンドが現在のシェルで強制的に実行するためです。

この手法は、機能に対して複雑すぎるか、開発中の頻繁に編集されるコマンドシーケンスに役立ちます。一度alias入力すると.bash_aliases、再初期化せずにスクリプトを自由に編集できます。

次のことに注意してください。

/ コマンドで呼び出す必要があるスクリプトを作成する場合、これを確認する方法は2つあります。.source

  1. 何らかの理由で、./で呼び出されるスクリプトはsource実行可能である必要はありません。したがって、単にこの許可を削除すると、「$ PATH」でスクリプトが見つからないか、明示的なパスで呼び出されると許可エラーが発生します。

  2. または、スクリプトの先頭で次のトリックを使用できます。

bind |& read && { echo 'Must be run from "." or "source" command'; exit 1; }

これは、bindサブシェルで警告が発行readされるためです。エラーステータスはありません。したがって、入力なしでエラーを出すために使用されます。


の情報をありがとう.。私は. .bashrc何度もやってきましたが、正確に何をするのかわかりませんでした.。それに似ていexportますか?
cst1992

2
@ cst1992-いいえ、コマンドはまったく異なります。環境にexport var内部変数varをコピーし、サブシェルの変数として継承およびインポートしますが、親シェルには影響しません。通常、サブシェルはスクリプトを実行するために作成され、それが行った変更(エクスポートされた変数を含む)は、完了すると失われます。スクリプトがシェルで変数を設定するには、そのシェルで実行する必要があり、これが.コマンドの動作です。サブシェルを作成せずにスクリプトを実行します。奇妙なことに、実行されるスクリプトに.は実行可能権限が必要ありません。
AFH

情報をありがとう。この情報を投稿に含めることを強くお勧めします。これは便利であり、率直に言って、コメントは明日そこにあるという保証はありません。
cst1992

@ cst1992-元の質問に対処しましたが、付随的な問題で答えが乱雑になりたくありません。コマンド.exportコマンドの説明を探している場合、この質問のタイトルはここで答えを期待することにはならないので、私の答えをそのままにしておきますが、コメントをありがとう。
AFH

一般に+1、ただし特にエイリアス。ソースを作成する必要のあるスクリプトがいくつかありますが、そのように実行することを常に忘れています。エイリアスはそれをうまく処理します。
ジョー

13

単一のコマンドではありませんが、使用するすべてのパス!$(シェル履歴内の前のコマンドの最後の引数)を再入力する必要はありません。

例:

mkdir -p /arbitrarily/long/path
cd !$

1

エイリアスを作成する。独自のコマンドを作成する非常に一般的な方法。

その場でエイリアスを作成できます。

alias myalias='mkdir -p /arbitrarily/long/path; cd /arbitrarily/long/path'

それでおしまい。そのエイリアスを(現在のセッションだけでなく)永続的に保持する場合は、そのコマンドをドットファイル(通常は〜/ .bash_aliasesまたは〜/ .bash_profile)に入れます。


4
長いディレクトリ名はハードコーディングされているため、このエイリアスが他のプロセスによって定期的に破棄されない限り、このエイリアスはあまり役に立ちません。
jlliagre

1

すでに提案されていることに加えて、thefuckをお勧めします。これは、間違いを修正してシェルプロセスを合理化するためのPythonフレームワークです。このツイートに触発され、あなたがしなければならないことはあなたの設定されたエイリアスを入力するだけで(デフォルトでfuck)、それはあなたの前のコマンドを修正しようとします。その修正の1つは次のように動作します。

/etc $ cd somedir
bash: cd: No such file or directory
/etc $ fuck
mkdir somedir && cd somedir
/etc/somedir $ 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.