38478


ローカルで定義、初期化した変数を使ってリモートシェル上でsedコマンドを使いたいと考えております。  
例を示すと

[code]

    local.sh
    #!/bin/bash
    string="hello"
    ssh host  'sed -i -e s/world/${string}/g /home/user/test.txt'
    
[/code]

このスクリプトを実行した際にリモート上のtest.txtでworld -> hello の置換が実行されることが理想です。  
この時どのように変数を指定すればよろしいでしょうか？


CC BY-SA 3.0
2017-10-05T06:31:57.717
38460
2017-10-07T02:32:50.323
19500
question
bash ssh sed
リモートシェルでローカルシェルの変数を参照したい


解決しました。

[code]

    string="hello"
    sed -i -e "sed -i -e 's/world/$string/g' /home/user/text.txt"
    
[/code]

でできました


CC BY-SA 3.0
2017-10-05T06:59:56.050
38461
2017-10-05T06:59:56.050
19500
38460
answer


fumiyas さんもおっしゃっていますが、 sed と ssh
組み合わせてやろうとすると、いくつか制御文字が使われた場合などで、バグが発生しています。まず具体例から。

質問者さんがやりたいことは、 world -> hello であるならば、ひとまず以下で達成できます。

[code]

    : ${SSH_TO:=host}
    TARGET_FILE=/home/ec2-user/test.txt
    FROM_STRING=world
    TO_STRING=hello
    ssh "$SSH_TO" sed -e "s/${FROM_STRING}/${TO_STRING}/g" $TARGET_FILE
    
[/code]

しかしこれは、変数に sed の制御文字が入ってきた時点で正しく動作しなくなってしまいます。

[code]

    : ${SSH_TO:=host}
    TARGET_FILE=/home/ec2-user/test.txt
    FROM_STRING=world
    TO_STRING=hel/lo
    ssh "$SSH_TO" sed -e "s/${FROM_STRING}/${TO_STRING}/g" $TARGET_FILE
    # sed: -e expression #1, char 13: unknown option to `s'
    
[/code]

これを解消するためには、 sed ではなく awk を用います。awk だと環境変数から直接文字列を参照できます。また、 ssh
は引数をスペースでつなげて文字列として対象ホストで実行します。これを正しく取り扱うために、環境変数のセットコマンドにはエスケープを施します。これをスクリプトにすると次。

[code]

    #!/bin/sh
    
    awk_script() {
        cat <<"EOF"
    { gsub(ENVIRON["FROM_STRING"], ENVIRON["TO_STRING"]); print }
    EOF
    }
    
    # 1: var_name
    # 2: content
    ssh_set_variable() {
        cat <<EOF
    ${1}='$(printf '%s\n' "$2" | sed -e "s/'/\\'/g")'
    EOF
    }
    
    : ${SSH_TO:=host}
    TARGET_FILE=/home/ec2-user/test.txt
    TO_STRING='any string should be allowed...'
    FROM_STRING=world  # any should be OK also
    ssh "$SSH_TO" \
        "$(ssh_set_variable FROM_STRING "${FROM_STRING}") " \
        "$(ssh_set_variable TO_STRING "${TO_STRING}") " \
        awk \'"$(awk_script)"\' \'"${TARGET_FILE}"\'
    
[/code]

スクリプトの解説を書こうと思いましたが、このスクリプトを書くので力尽きてしまったので、ひとまず動くものを共有しています。。


CC BY-SA 3.0
2017-10-06T03:52:38.950
38478
2017-10-06T03:57:40.643
2017-10-06T03:57:40.643
754
754
38460
answer


sshでリモート側にローカルの環境変数を渡すためには双方に設定が必要です。

## ローカル側

.ssh/config(または/etc/sshd/ssh_config)に環境変数を送信する設定

[code]

    SendEnv string
    
[/code]

## リモート側

/etc/ssh/sshd_configにローカル側が送ってきた環境変数を受け入れる設定

[code]

    AcceptEnv string
    
[/code]

また、現状のスクリプトでは`string`はexportされてないので子プロセスからは参照されません。

[code]

    export string="hello"
    
[/code]

として環境変数として設定してください。


CC BY-SA 3.0
2017-10-07T02:32:50.323
38500
2017-10-07T02:32:50.323
5793
38460
answer