なぜ! !エイリアス内では動作しませんか?

なぜ! !エイリアス内では動作しませんか?

/etc/bashrcシステムファイルに次のエイリアスが設定されています。

alias root="sudo !!"

この目的は、sudoコースを使用して最後に使用したコマンドを実行することです。これは、history対話型シェルでbashrc実行したときに得られる実際のコマンドではなく、シェルが初期化されたときにファイルの最後のコマンドを置き換えます。sudo !!私もやってみましたが、alias root="sudo fc -s"あまり効果がありませんでした。

これはBASHがコマンド置換を実行する方法に関連している可能性があることを知っていますが、なぜこれが起こるのかを説明し、利用可能な代替品を提供できる人はいますか?

私はBASHバージョン3.2.51(1)-リリース(x86_64-apple-darwin13)を実行しています。

答え1

bash マンページの 2 ビットは、この動作の主要部分を説明します。

このHISTORY EXPANSIONセクションの:

履歴拡張は、シェルが行を単語に分割する前に行全体を読み取った直後に行われます。

このALIASESセクションの:

各単純コマンドの最初の単語(引用符がない場合)を調べて、エイリアスがあるかどうかを確認します。

したがって、基本的に歴史的な拡張は噴射前に起こる。エイリアス拡張は後で発生します。


代替ソリューション

私が考えることができる最良の方法は次のとおりです。

alias root='sudo $(fc -ln -1)'

これは単純なコマンドにはうまく機能しますが、より複雑なコマンドには調整が必要です。

alias root='sudo sh -c "$(fc -ln -1)"'

変更の理由は次のとおりです。

# alias root='sudo $(fc -ln -1)'
# echo "I AM $(whoami)"
I AM patrick
# root
"I AM $(whoami)"

ご覧のとおり、シェルの解析は行われませんでした。 use に変更するとsh -c "..."シェル解析が可能です。

# alias root='sudo sh -c "$(fc -ln -1)"'
# echo "I AM $(whoami)"
I AM patrick
# root
I AM root

別の方法(私はこれを最初に考えたので答えにそのまま残しますが、上記の方法ほど良くありません):

alias root='fc -e "sed -i -e \"s/^/sudo /\""'

このfc -eコマンドは、指定されたコマンドを実行し、以前に実行されたコマンドを含むファイルを渡します。そのファイルを実行し、sedコマンドの前にsudo

答え2

このようにエイリアスを使用することはできません。エイリアスはなどのパラメータを渡すことはできません!!。目的の効果を得るには、関数を代わりに使用できます。

function root() {
  sudo $(history | tail -2 | head -1 | awk '{$1=$2=$3=""; print $0}');
}

しかし、これはおおよその考えであり、いくつかの問題があるかもしれません。私の書き込みコマンドの出力は次のとおりです。

$ history
1081  20131205 08:00:12  ls
1082  20131205 08:00:13  history

したがって、この出力を解析する必要があります。上記では、履歴を実行して最後の2つのコマンドをインポートし、以前に実行されたコマンドである最後の2つのコマンドのうち最初のコマンドを取得します。その後、以前awkに実行したコマンドラインをそのままにして最初の4列を削除しました。

エイリアスとして?

私たちが出力を使用していることを考えると、historyBash機能を使用する理由はもうありません。前のコマンドをパラメータとして渡す場合は、これを行う必要がありますが、history今はこのコマンドを使用してインポートします。

$ alias root="sudo \$(history | tail -2 | head -1 | awk '{\$1=\$2=\$3=\"\"; print \$0}')"

上記は、エイリアスに変換するのに必要な、より厳しいエスケープ処理を除いて、この関数と同様に機能します。

関連情報