iTerm2:如何从远程会话触发本地命令?
iTerm2: How can I trigger a local command from a remote session?
iTerm2 shell integration 有一些巧妙的技巧,比如它的 it2copy
命令,即使我通过 ssh 登录到远程机器,它也会复制到本地剪贴板。
它可以用于运行任意shell命令吗?
例如,当我通过 ssh 登录时,我想执行命令以在我的本地计算机上打开一个编辑器。 VSCode 可以用这个命令打开远程目录:
code --remote ssh-remote+myserver /home/stuart/some-directory
我想从远程计算机上的 ssh 会话在本地触发该命令。
PS -- 我知道有一个替代方案:创建一个(嵌套的)ssh 连接 back 到我的本地机器以通过 ssh 执行命令,而不是使用iTerm2 的后台通道。但这有各种缺点,因此这个问题。
我也知道 ~/.ssh/config
中的 PermitLocalCommand
选项,它允许我发送转义码 (~C
),然后是本地命令 (!code --remote ...
).但我希望有一个可以在脚本或 bash 别名中使用的解决方案。
例如,如果 it2local
存在,我会这样使用它:
alias code_here='it2local "code --remote ssh-remote+$(uname -n) $(pwd)"'
如果仅通过 ssh 就可以做到这一点,我很想听听。
正确的方法是通过 iTerm2 Triggers,只要终端输出中出现特定模式,它就可以 运行 任意命令(以及其他选项)。
我上面描述的假设的 it2local
命令只需要向您的终端回显一些预定义的触发模式,以及您要执行的命令。
就我而言,我没有实施通用 it2local
命令。 (也许我稍后会更新这个答案。)现在,我已经实现了一个脚本来满足我的特定用例:使用 VSCode 打开远程文件。我使用的代码如下所示。
#!/bin/sh
#
# This file contains the code and instructions to set up an iTerm2 "Trigger" from a
# remote ssh session that will open up VSCode on your local machine to edit a
# file on the remote server over ssh.
#
# Author: Stuart Berg
# https://github.com/stuarteberg
# bergs@janelia.hhmi.org
#
# SETUP OVERVIEW
# --------------
# - Install the VS Code Remote Development Extension Pack
# - Ideally, setup passwordless ssh access to the remote machines you want to access
# - Place this script somewhere on your local machine (and make sure it's executable).
# - Copy the localcode() shell function below into your remote machine's .bashrc
# - Define the Trigger in iTerm2 as defined below.
#
# Notes:
# Docs for iTerm2 Triggers: https://iterm2.com/documentation-triggers.html
# Docs for VSCode Remote Extension: https://code.visualstudio.com/docs/remote/remote-overview
# - CLI: https://github.com/microsoft/vscode-remote-release/issues/585#issuecomment-536580102
# iTerm2 Preferences Setup
# ------------------------
#
# In your iTerm2 preferences, set up a Trigger (Profiles > Advanced > Triggers > Edit)
#
# Regular Expression: .*ITERM-TRIGGER-open-with-local-vscode-remote ([^ ]+) ([^ ]+) (([^ ]+ ?)+)
# Action: Run Command...
# Parameters: /path/to/this/script
#
# Tip: For additional feedback, try adding a duplicate entry with a "Post Notifcation" action.
# HOW TO TEST
# -----------
#
# NOTE: The new trigger will not be active for already-open terminal sessions.
# Open a new terminal after you add the trigger to your preferences.
#
# To test it, ssh into the remote machine, and try the 'localcode' function:
#
# localcode .
# localcode /some/dir
# localcode /some/file
# localcode /some/file remote-machine-name
#
# If something is going wrong, inspect /tmp/iterm-vscode-trigger.log
#
# Put this in your remote ~/.bashrc
#
localcode() (
# Tell zsh to use bash-style arrays
setopt ksh_arrays 2> /dev/null || true
CMD=ITERM-TRIGGER-open-with-local-vscode-remote
MACHINE=${LOCALCODE_MACHINE-submit}
FILENAMES=( "$@" )
if [[ ${#FILENAMES[@]} == 0 ]]; then
FILENAMES=.
fi
if [[ ${#FILENAMES[@]} == 1 && -d ${FILENAMES[0]} ]]; then
FILENAMES[0]=$(cd ${FILENAMES[0]}; pwd)
FTYPE=directory
else
# Convert filenames to abspaths
for (( i=0; i < ${#FILENAMES[@]}; i++ )); do
FN=${FILENAMES[i]}
if [[ -f ${FN} ]]; then
DIRNAME=$(cd $(dirname ${FN}); pwd)
FILENAMES[i]=${DIRNAME}/$(basename ${FN})
FTYPE=file
else
1>&2 echo "Not a valid file: ${FN}"
exit 1
fi
done
fi
echo ${CMD} ${FTYPE} ${MACHINE} ${FILENAMES[@]}
)
export -f localcode
#
# Copy this whole file onto your local machine, or at least the following lines.
# Make sure it is executable (chmod +x /path/to/this/script)
#
trigger_vscode_remote_editing() (
# Tell zsh to use bash-style arrays
setopt ksh_arrays 2> /dev/null || true
# The git extension runs 'git status -z -u' on the remote machine,
# which takes a very long time if the remote directory is a git repo
# with a lot of untracked files.
# That can be fixed if you configure .gitignore appropriately,
# but for my purposes it's easier to just disable git support when editing remote files.
# If you want git support when using remote SSH, then comment out this line.
# See: https://github.com/microsoft/vscode-remote-release/issues/4073
VSCODE='/usr/local/bin/code'
VSCODE="${VSCODE} --disable-extension vscode.git --disable-extension vscode.github --disable-extension waderyan.gitblame"
LOGFILE=/tmp/iterm-vscode-trigger.log
FTYPE=
MACHINE=
FILEPATHS=( "$@" )
FILEPATHS=( "${FILEPATHS[@]:2}" )
TS="["$(date "+%Y-%m-%d %H:%M:%S")"]"
echo "${TS} Triggered: ""$@" >> ${LOGFILE}
# https://github.com/microsoft/vscode-remote-release/issues/585#issuecomment-536580102
if [[ "${FTYPE}" == "directory" ]]; then
CMD="${VSCODE} --remote ssh-remote+${MACHINE} ${FILEPATHS[@]}"
echo "${TS} ${CMD}" >> ${LOGFILE}
${CMD}
elif [[ "${FTYPE}" == "file" ]]; then
for FN in ${FILEPATHS[@]}; do
CMD="${VSCODE} --file-uri vscode-remote://ssh-remote+${MACHINE}${FN}"
echo "${TS} ${CMD}" >> ${LOGFILE}
${CMD}
done
else
echo "${TS} Error: Bad arguments." >> ${LOGFILE}
exit 1
fi
)
trigger_vscode_remote_editing "$@"
对于仍然想这样做的人:
我的解决方案受到@StuartBerg 的启发。非常感谢。
- 在iTerm2中,找到触发器:
iTerm2 -> Perenfences -> Profiles -> Advanced -> Triggers -> Edit
,设置触发器如下(设置后记得重启iTerm2):
# open a folder
- Regular Expression: ^open this folder in local vscode\(s\):(.+)
- Action: Run Command...
- Parameters: /path/to/your/vscode --folder-uri=vscode-remote://ssh-remote+${your remote ip}
# open a file
- Regular Expression: ^open this file in local vscode\(s\):(.+)
- Action: Run Command...
- Parameters: /path/to/your/vscode --file-uri=vscode-remote://ssh-remote+${your remote ip}
- 在远程服务器中设置命令别名,通常在
~/.bashrc
for linux(大多数code
别名的行为与本地相同terminal,除了任何不在服务器中存在的文件都不会被打开):
# pay attention to " and '
alias code='func(){
if [[ "" == "." ]]; then
CODE_PATH=$(pwd | tr -d "\n\r");
else
if [[ "" == /* ]]; then
CODE_PATH="";
else
CODE_PATH=$(pwd | tr -d "\n\r")/"";
fi;
fi;
if [[ -d $CODE_PATH ]]; then
echo open this folder in local vscode"("s")":$CODE_PATH;
else
if [[ -f $CODE_PATH ]]; then
echo open this file in local vscode"("s")":$CODE_PATH;
else
echo No such file or directory: $CODE_PATH;
fi;
fi;
};func'
- 使别名生效:
$ source ${path/to/your/alias/file}
- 在ssh终端中,
cd
到你想在本地打开的目录vscode(或者使用绝对路径以/
[=44=开头]) 并执行:
# open the current folder
$ code .
# output:
# open this folder in local vscode(s):/folder/you/want/to/open
# open a file or a folder in current directory
$ code ${filename or folder}
# output:
# open this file(folder) in local vscode(s):/path/you/want/to/open
# open an absolute path, i.e, any path that starts with `/`
$ code `/${absolute/path}`
如果您在本地设置远程服务器的 ssh 密钥,那么目录 /path/you/want/to/open
将在您的本地 vscode 中打开。
PS:
^
、\(s\)
和 '('s')'
是有意添加的,目的是在配置文件和触发器 Regular Expression
之间做一些区别,这样触发器就不会在您时意外触发打开别名配置文件。您可以随意修改它。
iTerm2 shell integration 有一些巧妙的技巧,比如它的 it2copy
命令,即使我通过 ssh 登录到远程机器,它也会复制到本地剪贴板。
它可以用于运行任意shell命令吗?
例如,当我通过 ssh 登录时,我想执行命令以在我的本地计算机上打开一个编辑器。 VSCode 可以用这个命令打开远程目录:
code --remote ssh-remote+myserver /home/stuart/some-directory
我想从远程计算机上的 ssh 会话在本地触发该命令。
PS -- 我知道有一个替代方案:创建一个(嵌套的)ssh 连接 back 到我的本地机器以通过 ssh 执行命令,而不是使用iTerm2 的后台通道。但这有各种缺点,因此这个问题。
我也知道 ~/.ssh/config
中的 PermitLocalCommand
选项,它允许我发送转义码 (~C
),然后是本地命令 (!code --remote ...
).但我希望有一个可以在脚本或 bash 别名中使用的解决方案。
例如,如果 it2local
存在,我会这样使用它:
alias code_here='it2local "code --remote ssh-remote+$(uname -n) $(pwd)"'
如果仅通过 ssh 就可以做到这一点,我很想听听。
正确的方法是通过 iTerm2 Triggers,只要终端输出中出现特定模式,它就可以 运行 任意命令(以及其他选项)。
我上面描述的假设的 it2local
命令只需要向您的终端回显一些预定义的触发模式,以及您要执行的命令。
就我而言,我没有实施通用 it2local
命令。 (也许我稍后会更新这个答案。)现在,我已经实现了一个脚本来满足我的特定用例:使用 VSCode 打开远程文件。我使用的代码如下所示。
#!/bin/sh
#
# This file contains the code and instructions to set up an iTerm2 "Trigger" from a
# remote ssh session that will open up VSCode on your local machine to edit a
# file on the remote server over ssh.
#
# Author: Stuart Berg
# https://github.com/stuarteberg
# bergs@janelia.hhmi.org
#
# SETUP OVERVIEW
# --------------
# - Install the VS Code Remote Development Extension Pack
# - Ideally, setup passwordless ssh access to the remote machines you want to access
# - Place this script somewhere on your local machine (and make sure it's executable).
# - Copy the localcode() shell function below into your remote machine's .bashrc
# - Define the Trigger in iTerm2 as defined below.
#
# Notes:
# Docs for iTerm2 Triggers: https://iterm2.com/documentation-triggers.html
# Docs for VSCode Remote Extension: https://code.visualstudio.com/docs/remote/remote-overview
# - CLI: https://github.com/microsoft/vscode-remote-release/issues/585#issuecomment-536580102
# iTerm2 Preferences Setup
# ------------------------
#
# In your iTerm2 preferences, set up a Trigger (Profiles > Advanced > Triggers > Edit)
#
# Regular Expression: .*ITERM-TRIGGER-open-with-local-vscode-remote ([^ ]+) ([^ ]+) (([^ ]+ ?)+)
# Action: Run Command...
# Parameters: /path/to/this/script
#
# Tip: For additional feedback, try adding a duplicate entry with a "Post Notifcation" action.
# HOW TO TEST
# -----------
#
# NOTE: The new trigger will not be active for already-open terminal sessions.
# Open a new terminal after you add the trigger to your preferences.
#
# To test it, ssh into the remote machine, and try the 'localcode' function:
#
# localcode .
# localcode /some/dir
# localcode /some/file
# localcode /some/file remote-machine-name
#
# If something is going wrong, inspect /tmp/iterm-vscode-trigger.log
#
# Put this in your remote ~/.bashrc
#
localcode() (
# Tell zsh to use bash-style arrays
setopt ksh_arrays 2> /dev/null || true
CMD=ITERM-TRIGGER-open-with-local-vscode-remote
MACHINE=${LOCALCODE_MACHINE-submit}
FILENAMES=( "$@" )
if [[ ${#FILENAMES[@]} == 0 ]]; then
FILENAMES=.
fi
if [[ ${#FILENAMES[@]} == 1 && -d ${FILENAMES[0]} ]]; then
FILENAMES[0]=$(cd ${FILENAMES[0]}; pwd)
FTYPE=directory
else
# Convert filenames to abspaths
for (( i=0; i < ${#FILENAMES[@]}; i++ )); do
FN=${FILENAMES[i]}
if [[ -f ${FN} ]]; then
DIRNAME=$(cd $(dirname ${FN}); pwd)
FILENAMES[i]=${DIRNAME}/$(basename ${FN})
FTYPE=file
else
1>&2 echo "Not a valid file: ${FN}"
exit 1
fi
done
fi
echo ${CMD} ${FTYPE} ${MACHINE} ${FILENAMES[@]}
)
export -f localcode
#
# Copy this whole file onto your local machine, or at least the following lines.
# Make sure it is executable (chmod +x /path/to/this/script)
#
trigger_vscode_remote_editing() (
# Tell zsh to use bash-style arrays
setopt ksh_arrays 2> /dev/null || true
# The git extension runs 'git status -z -u' on the remote machine,
# which takes a very long time if the remote directory is a git repo
# with a lot of untracked files.
# That can be fixed if you configure .gitignore appropriately,
# but for my purposes it's easier to just disable git support when editing remote files.
# If you want git support when using remote SSH, then comment out this line.
# See: https://github.com/microsoft/vscode-remote-release/issues/4073
VSCODE='/usr/local/bin/code'
VSCODE="${VSCODE} --disable-extension vscode.git --disable-extension vscode.github --disable-extension waderyan.gitblame"
LOGFILE=/tmp/iterm-vscode-trigger.log
FTYPE=
MACHINE=
FILEPATHS=( "$@" )
FILEPATHS=( "${FILEPATHS[@]:2}" )
TS="["$(date "+%Y-%m-%d %H:%M:%S")"]"
echo "${TS} Triggered: ""$@" >> ${LOGFILE}
# https://github.com/microsoft/vscode-remote-release/issues/585#issuecomment-536580102
if [[ "${FTYPE}" == "directory" ]]; then
CMD="${VSCODE} --remote ssh-remote+${MACHINE} ${FILEPATHS[@]}"
echo "${TS} ${CMD}" >> ${LOGFILE}
${CMD}
elif [[ "${FTYPE}" == "file" ]]; then
for FN in ${FILEPATHS[@]}; do
CMD="${VSCODE} --file-uri vscode-remote://ssh-remote+${MACHINE}${FN}"
echo "${TS} ${CMD}" >> ${LOGFILE}
${CMD}
done
else
echo "${TS} Error: Bad arguments." >> ${LOGFILE}
exit 1
fi
)
trigger_vscode_remote_editing "$@"
对于仍然想这样做的人:
我的解决方案受到@StuartBerg 的启发。非常感谢。
- 在iTerm2中,找到触发器:
iTerm2 -> Perenfences -> Profiles -> Advanced -> Triggers -> Edit
,设置触发器如下(设置后记得重启iTerm2):
# open a folder
- Regular Expression: ^open this folder in local vscode\(s\):(.+)
- Action: Run Command...
- Parameters: /path/to/your/vscode --folder-uri=vscode-remote://ssh-remote+${your remote ip}
# open a file
- Regular Expression: ^open this file in local vscode\(s\):(.+)
- Action: Run Command...
- Parameters: /path/to/your/vscode --file-uri=vscode-remote://ssh-remote+${your remote ip}
- 在远程服务器中设置命令别名,通常在
~/.bashrc
for linux(大多数code
别名的行为与本地相同terminal,除了任何不在服务器中存在的文件都不会被打开):
# pay attention to " and '
alias code='func(){
if [[ "" == "." ]]; then
CODE_PATH=$(pwd | tr -d "\n\r");
else
if [[ "" == /* ]]; then
CODE_PATH="";
else
CODE_PATH=$(pwd | tr -d "\n\r")/"";
fi;
fi;
if [[ -d $CODE_PATH ]]; then
echo open this folder in local vscode"("s")":$CODE_PATH;
else
if [[ -f $CODE_PATH ]]; then
echo open this file in local vscode"("s")":$CODE_PATH;
else
echo No such file or directory: $CODE_PATH;
fi;
fi;
};func'
- 使别名生效:
$ source ${path/to/your/alias/file}
- 在ssh终端中,
cd
到你想在本地打开的目录vscode(或者使用绝对路径以/
[=44=开头]) 并执行:
# open the current folder
$ code .
# output:
# open this folder in local vscode(s):/folder/you/want/to/open
# open a file or a folder in current directory
$ code ${filename or folder}
# output:
# open this file(folder) in local vscode(s):/path/you/want/to/open
# open an absolute path, i.e, any path that starts with `/`
$ code `/${absolute/path}`
如果您在本地设置远程服务器的 ssh 密钥,那么目录 /path/you/want/to/open
将在您的本地 vscode 中打开。
PS:
^
、\(s\)
和 '('s')'
是有意添加的,目的是在配置文件和触发器 Regular Expression
之间做一些区别,这样触发器就不会在您时意外触发打开别名配置文件。您可以随意修改它。