假设我编写了以下巧妙的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
所以,问题是:如何简单而优雅地(即,如果必须发生大量符号修改,那么“编写一个专门的工具来执行此操作”可能就是答案)将命令行给出的文字命令填充到现场例如,在ssh
命令中,以便一切都按照用户(我)期望的 3 个月后的方式运行? (考虑所有必要的转义字符)
到目前为止,我提出的复杂解决方案是解决获取 cli 输入数据并将其放入文件中的更简单的问题:
- 找出一种未知的方法来消化 cli 字符串的全部内容(包括管道字符)
- 将该内容放入 tmp 目录中的 shell 脚本中
- scp 该 shell 脚本到带有一些散列名称的远程计算机
- 运行该 shell 脚本,而
ssh
不是尝试管理字符转义
但是,理想情况下,有某种方法可以指定 CLI 字符串并将其放入 ssh 双引号子句中,并正确评估转义字符。
我想到的工具是m4
、tmp
和sponge
,但我仍然无法真正想出一种方法来将命令消化为字符串文字并将其弹出到命令字符串中而不通过该行ssh
参与。bash
#!/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 将在 bangs 之后扩展别名(“历史扩展”);如果不修改 bash 源代码或直接挂钩到 readline 代码,则无法在扩展!!
或之类的内容之前获取命令行。!:$
如果您没有主动使用该功能(主要是敷衍),您可以使用 安全地关闭它set +H
。