SSHコマンド:二重引用符の問題を回避する方法は?

SSHコマンド:二重引用符の問題を回避する方法は?

私が次のような賢いスクリプトを書いているとしましょうrsh.sh

#!/usr/bin/env bash
git_project=`git rev-parse --show-toplevel`
git_prefix=`git rev-parse --show-prefix`
name=$(basename '${git_project}')
ssh $1 "cd '${name}' && $2"

私のCLIでは、次のように書きました。

$: rsh.sh vm ls

(働くと仮定してタイプミスをしておいてください)

rsh.sh次に、コマンドプロンプトと同じで、二重引用符と一重引用符の技術を完全に自由に利用できると仮定します。

# and maybe I'll have to add more escapes
$: rsh.sh vm "cat foo | awk -f '{print(\"bar\")}'"

# but ideally I could skip all that, not parse the cmd string using bash, and write
$: rsh vm cat foo | awk -f '{print("bar")}' 

# however, here, the command will be partitioned by the "|" symbol, and only the 
# first clause is going to be evaluated by the script

したがって、問題は単純でエレガントに(つまり、多くのシンボル修正が必要な場合は「これを行うための特別なツールを作成する」ことが答えかもしれません)、コマンドラインで提供されるリテラルコマンドをフィールドに埋める方法です。たとえば、ssh3ヶ月後にすべてがユーザー(私)が期待どおりに機能するようにコマンドで? (必要なすべてのエスケープ文字を考慮)


これまで私が思いついた複雑な解決策は、cli入力データを取得してファイルに保存する簡単な問題を解決することです。

  1. cli文字列(パイプ文字を含む)の内容全体を消化する未知の方法を見つける
  2. この内容をtmpディレクトリのシェルスクリプトに入れます。
  3. このシェルスクリプトをハッシュされた名前を使用してリモートシステムにscpします。
  4. ssh文字エスケープを管理する代わりに、このシェルスクリプトを実行してください。

ただし、理想的にはCLI文字列を指定し、それをssh二重引用符句に入れて、エスケープ文字が正しく評価されるようにする方法があります。

気に入るツールはm4tmpおよびspongeですが、コマンドを文字列リテラルに消化し、行を含まずにコマンド文字列に表示する方法をまだ把握できませんsshbash#!/bin/bash

ベストアンサー1

何のために私の考えではこれが実際の問題です(=拡張されていない生のコマンドラインを取得し、他のコマンドに引数として渡します。)、「エイリアス+コメント+履歴」トリックを使用できます。このトリックはこことstackoverflowで多くの答えを見つけることができます。

alias ush='_ush #'
_ush(){
    local l=$(fc -nl -0)  # get the current command line from history
    l=${l#*ush}           # strip it up to and including the name of the alias (ush)
    l=${l#"${l%%[! ]*}"}  # strip any spaces after the name of the alias
    local h=${l%% *}      # get the user@host part of the command
    l=${l#"$h"}           # get the rest of the command line
    ssh "$h" "$l"         # run the above verbatim on user@host
}

ush user@host echo foo > file
   # will create "file" on the remote host
ush user@host foo | bar
   # will run both foo and bar on the remote host

!!注:bashは、bashソースコードを変更したりreadlineコードに直接接続したりすることなく、前髪の後にエイリアスを拡張します(「歴史的拡張」)。拡張する前にコマンドラインを取得する方法はありません。!:$その機能を積極的に使用しない場合(ほとんどの形式では)、安全にオフを使用できますset +H

おすすめ記事