最後のコマンドでスラッシュをバックスラッシュに置き換えます


10

コマンドcd C:\foo\bar\をPowerShellからCygwinにコピーしましたが、それが実行されることを間違えて予想していました。私は今、すべて交換する置換を実行しようとしている\とし/

$ !!:gs/\\/\/
bash: :gs/\\/\/: substitution failed

なぜ代替が失敗したのかわからない。

私も試しました:

$ !!:gs/\\/q

置き換えが問題であったかどうかを確認します。そうではありません。今私は好奇心が強い!

「置換に失敗しました」と表示されるのはなぜですか?


2
今のところcygwinはありませんが、Windowsのパスが機能していると思いました...引数を一重引用符で囲みましたか?すなわちcd 'C:\foo\bar'
MPY

@mpyこれも実際に動作します!私が代理で立ち往生していないことを知りませんでした。
Tanner Faulkner 2017年

1
「zshを使用した回答にも対応できます」。オリジナル!!:gs/\\/\/はzshで動作します…
Kamil Maciorowski 2017年

@TannerFaulkner fc -s '\'='/' -1は、Ubuntu LTSのデフォルトのbashで動作します。Cygwinでも動作するかどうか教えてください。私は答えにもっと言葉を投稿しました。
Hastur

1
ここでの一般的なbashの動作は、置換がで発生する前に、バックスラッシュがエスケープとして処理されることです!!:gs/\\/\//。@Hastur fc -s '\'='/' -1は期待される動作をします。これはbashのバグかもしれません。
quixotic 2017年

回答:


6

スラッシュは置換コマンドの区切り文字でもあるため、置換を早く終了しないように、置換文字列としてエスケープする必要があります。

!!:gs/\\/\//

またはコメントで示唆されているように、区切り文字としてスラッシュ以外のものを使用する

!!:gs|\\|/|

しかし、これはtcsh(私がいる場所に一般的に割り当てられているシェルで)動作するbashように見えますが、エスケープは最初の引数では機能しないように見えるため、コマンドを機能させることができません:s


喜びがない:(同じエラーi.imgur.com/QFQR0xF.png
Tanner Faulkner

1
ただの注釈:!!:gs|\\|/もう少し読みやすいかもしれません。
mpy

1
bashで動作させることができませんでした。の最初の引数は:s本当の正規表現ではないようです
添え字

4

短い答え:bashの組み込みfc(修正コマンド)

fc履歴のコマンドを編集および再実行するために作成さた、bashシェルに組み込まれたコマンドです。
それはあまりにもCygwinでは存在し、それは私がテストしたすべてのLinuxディストリビューションで動作します:

fc  -s '\'='/' -1

いくつかの説明

  • fc履歴リストからコマンドをリストまたは編集して再実行するbash 組み込みコマンドです。
  • -1履歴の最後のコマンドを取ります。も!!次のように定義されている(から読み取られるman bash) ことに注意してください。

    !! Refer to the previous command. This is a synonym for!-1 '。

  • -sパターンを別のパターンに置き換えます。今回はhelp fc(組み込みコマンドso help)から:

    `fc -s [pat = rep ...] [command] '形式では、置換OLD = NEWが実行された後にCOMMANDが再実行されます。

    [OK]を彼らは意味pat=repの代わりにOLD=NEW...

  • パターンは、我々は引用符でそれらを保護するために持っているので、シェルによって読み込まれます:'\''/'

なぜ「代替が失敗した」のかについて、いくつかの言葉

s 修飾子が(まだ)バックスラッシュ文字の置換を実装していないようです\、それはエスケープ文字です。確かに、たとえばbash履歴拡張のgnuバージョンのコードが表示されるはずです(しかし、あなたがしようとしていることを取得するための上記のコマンドがあったので...私はそれを怠惰にしています...)。

いくつかのメモ:

  1. 私たちは、それが私たちと一緒sedに動作しているのを見つけるそれぞれのRegExで動作すると思いがちですが、それは保証されていません。バックスラッシュは拡張のエスケープ文字であり、問​​題はここにあります。さらに、拡張の動作はshoptオプションに関連しているので、ケースバイケースで見始める必要があります...

  2. 文字列cd C:\Foo\Barをbashシェルに貼り付けると、文字列が展開され、インタプリタからはと表示されcd C:FooBarます。この形式では、$_内部変数にも格納されます。
    代わりに貼り付けcd "C:\Foo\Bar"たりcd 'C:\Foo\Bar'$_ 変数に入れたりすると、が見つかりますC:\Foo\Bar
    履歴展開は単語にシェル休憩、その前に、あなたはいくつかでそれを使用するために開始するように誘惑することができる、完全な行が読み込まれた直後に行われているのでbashism(多分追加することからいくつかの派生で、例えば、多かれ少なかれ、プレーン:pまたは:q""、解析など...)

    !!:0 ${_//\\/\/}

    安全ではないことを覚えておくことは一瞬で起動するパスと一緒にプレイするために、ファイル名は、Windowsのクリップボードから来る場合は特に、(一般的にページ読み込みなぜない解析をls、それは基本的に、使用のタブに可能性が関連していますスペースと改行は、ファイル名とディレクトリのものの正しい文字として...)。
    さらに、マウスキャプチャされたテキスト貼り付けるときに、先頭のスペースも貼り付ける場合があります。これにより、コマンドが履歴で終了するのを防ぐことができます(シェルオプションに依存します...)。もしそうなら、あなたのフォロー!!は制御されていないコマンドになります...(別の回答の例を参照してください)。これは、不必要な具体的なリスクです。

結論

履歴の展開により、履歴リストの単語が入力ストリームに導入され、コマンドの繰り返し、現在の入力行への前のコマンドの引数の挿入、または前のコマンドのエラーの修正が簡単になります。

それが簡単でない場合、私たちは何か間違ったことをしていると思い始めます ;-)


広告吐き気:少し実験

私はhistverifyシェルで有効にしました...

shopt -s histverify
echo C:\Foo\Bar
!!:s|C|D| {1,2}A

それから私は押すEnter確認された拡張として私は見つけます

echo D:\Foo\Bar {1,2}A

それから私はEnterもう一度押します、そしてそれは反響します

D:FooBar 1A 2A

これsubstitution failedは、がBrace展開の前に処理された履歴展開で生成されたことを示しているようです。まず最初にs履歴修飾子が\実際の正規表現としての文字の置換を(まだ)処理していないことを確認しているようです。 ..


2

sed結果を代入して実行するために使用できます。

そのようなコマンドにはいくつかの可能な変形がありますが、私のbashではこれだけが機能しました:

A=$(echo "!!\\" | sed 's,\\,/,g');eval $A

\\追加された!!場合には、バックスラッシュで終了最後のコマンドです。これがないと、シェルは混乱し、行の継続を要求します。

これをファイルのbash関数として追加することもできます~/.bashrc

function slash {
   A=$(history | tail -n 2 | head -n 1 | cut -c 8- | sed 's,\\,/,g')
   eval $A
}

これがWindows上の私のBashでどのように機能するかです:

バッシュ

A=コマンドがシェル変数に正しい値を割り当てる方法を説明するにはA

  • tailコマンド履歴から最後の2行を取得し、cd \mnt\cその後に続く行を表示しslashます。の部分は、history | tail -n 2と書くこともできますhistory 2
  • head 最初の行を cd \mnt\c
  • cut によって提供される行番号を切り取ります history
  • sed すべてのアンチスラッシュをスラッシュに置き換えます
  • eval 変数の内容を実行します A

こんにちはハリー。私のGNU bashバージョン4.3.11(1)A=$(echo "!!\\" | sed 's,\\,/,g');eval $Aでは、コマンドがバックスラッシュで終了した場合は動作しません。あなたがC:\Foo\Bar\ 言ったように、あなたは例えば他にスペースを追加することを強いられます、シェルは行の継続を待ちます。Enterキーを2回押すこともできます。最初のケースでは、入手C:/Foo/Bar /スペースの前で(/;それはエラーが発生します第二に機能が正常に動作します。。
ハスター

この関数を書いたのは、(1)はるかに使いやすく、(2)ワンライナーが実装に依存しすぎているように見えたためです。
ハリーマク2017年

-1

あなたはこれを行うことができないと思います。もう一度コピー/貼り付けする必要があります。

代替コマンドは任意の区切り文字を受け入れるため、この問題は、代替コマンドの区切り文字でもあるスラッシュとは関係ありません。問題は、置換されるバックスラッシュについてです。これは、右側の文字の単純な役に立たないエスケープメントとして既に処理されています。

したがって、substituteコマンドを呼び出すと、バックスラッシュはすでにソースから消えています。そのままコマンドを再呼び出ししてみてください(!!)。を含むまったく同じコマンドを出力するのc:\fooではなく、コマンドを実行して、結果としてc:foo

そして、明らかに、欠けている文字を見つけたり、置き換えたりすることはできません。そうしようとすると、エラーが発生します。


1
上手。このテストは、実際に動作するので、それは最終的に間違っている:echo c:\Foo続きます!!:gs,F,\\f,。しかし、バックスラッシュエスケープ自体を置き換えることは、苦痛のようです。
A.ロワゾー2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.