我试图让这个脚本工作(它应该做的是在远程服务器的最后一个日志文件中搜索一个字符串):
ssh -i $ssh_key_file ubuntu@$1 -t "cd /path/to/logs; grep \"POST api/orders \" `ls -Art | grep info | tail -n 1` -A 2 | grep \"'store_id' => '$2'\" -B 1; bash --login"
这个脚本
`ls -Art | grep info | tail -n 1`
应该返回给我最后一个日志文件,这是一个例子,如果我在远程服务器上单独运行该脚本:
$ ls -Art | grep info | tail -n 1
info-2019-04-10.log
此外,如果我通过硬编码日志文件名来运行与上面完全相同的脚本,它就可以正常工作:
ssh -i $ssh_key_file ubuntu@$1 -t "cd /path/to/logs; grep \"POST api/orders \" info-2019-04-10.log -A 2 | grep \"'store_id' => '$2'\" -B 1; bash --login"
我能够将这个(查找最后一个日志文件)脚本嵌入到其他 shell 脚本中,并且运行良好,如下所示:
ssh -i $ssh_key_file ubuntu@$1 -t "cd /path/to/logs; grep $2 `ls -Art | grep info | tail -n 1`; bash --login"
我在原始脚本中做错了什么?
更新
使用这个脚本
function totCreateOrder()
{
ssh -i "$ssh_key_file" ubuntu@"$1" -t<<EOF
cd /var/www/toters/storage/logs && grep "POST api/orders " "\$(ls -Art | grep info | tail -n 1)" -A 2 \
| grep "'store_id' => '"'$2'"'" -B 1
bash --login
EOF
}
正在返回这个奇怪的错误消息
totCreateOrder $prod1as 1006
Pseudo-terminal will not be allocated because stdin is not a terminal.
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1067-aws x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
Get cloud support with Ubuntu Advantage Cloud Guest:
http://www.ubuntu.com/business/services/cloud
74 packages can be updated.
0 updates are security updates.
New release '18.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
*** System restart required ***
我查看了该错误的含义并改为执行此操作
function totCreateOrder()
{
ssh -i $ssh_key_file ubuntu@$1 -t -t<<EOF
cd /var/www/toters/storage/logs && grep "POST api/orders " "\$(ls -Art | grep info | tail -n 1)" -A 2 \
| grep "'store_id' => '"'$2'"'" -B 1
EOF
}
但后来我收到此错误消息:
totCreateOrder $prod1as 1006
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1067-aws x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
Get cloud support with Ubuntu Advantage Cloud Guest:
http://www.ubuntu.com/business/services/cloud
74 packages can be updated.
0 updates are security updates.
New release '18.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
*** System restart required ***
Last login: Thu Apr 11 03:38:32 2019 from 185.81.141.32
1"$(ls -Art | grep info | tail -n 1)" -A 2 | grep "'store_id' => '"'1006'"'" -B
更新二
我正在逐行检查脚本。这在实现以下目标的意义上起作用:
- 登录到远程服务器
- 能够
ls -Art | grep info | tail -n 1
正确解析 在远程服务器上运行此命令:
grep "POST api/orders " "$(ls -Art | grep info | tail -n 1)" -A 2
函数测试(){ ssh -i $ssh_key_file ubuntu@$1 -t -t<
它返回了这个
test $prod1as
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1067-aws x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
Get cloud support with Ubuntu Advantage Cloud Guest:
http://www.ubuntu.com/business/services/cloud
74 packages can be updated.
0 updates are security updates.
New release '18.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
*** System restart required ***
Last login: Thu Apr 11 05:18:10 2019 from 185.81.141.85
ubuntu@ip-x-xx-xx:~$ cd /var/www/toters/storage/logs
-Art | grep info | tail -n 1)" -A 2 storage/logs$ grep "POST api/orders " "$(ls
[2019-04-11 04:10:39] production.INFO: POST api/orders [] []
[2019-04-11 04:10:39] production.INFO: array ( 'store_id' => '831', 'items' => array ( 0 => array ( 'additional_info' => '', 'addons' => array ( ), 'quantity' => 1, 'id' => 129369,
), 1 => array ( 'additional_info' => '', 'addons' => array ( ), 'quantity' => 1, 'id' => 133351, ), 2 => array ( 'additional_info' => '', 'addons' => ..
然而,当我像这样添加管道时,事情就坏了:
function test()
{
ssh -i $ssh_key_file ubuntu@$1 -t -t<<EOF
cd /var/www/toters/storage/logs
grep "POST api/orders " "\$(ls -Art | grep info | tail -n 1)" -A 2 | grep "'store_id' => '"'$2'"'" -B 1
EOF
}
它返回这个
$ test $prod1as 1006
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1067-aws x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
Get cloud support with Ubuntu Advantage Cloud Guest:
http://www.ubuntu.com/business/services/cloud
74 packages can be updated.
0 updates are security updates.
New release '18.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
*** System restart required ***
Last login: Thu Apr 11 05:33:22 2019 from 185.81.141.85
ubuntu@ip-10-0-1-39:~$ cd /var/www/toters/storage/logs
-Art | grep info | tail -n 1)" -A 2 | grep "'store_id' => '"'1006'"'" -B 1"$(ls
主要问题是:双引号中的反引号在本地扩展。通常我会推荐 here document,但在你的情况下你需要一个伪终端并且不能真正重定向标准输入(这是 here document 所做的)。无论如何使用
$()
而不是反引号并转义$
(或者你可以坚持使用反引号并转义它们,但$()
通常是首选)或单引号这个片段。这应该将整个$( … )
语法传递给远程端。您还应该确保远程 shell 将其用双引号引起来,因为很明显您不希望结果在这种情况下进行分词和模式匹配。一般来说,不应该解析
ls
. 我想很难用更健壮的东西替换你的代码,除非find
在远程端支持-printf
. 但是不知道是不是这样,所以我不打算改进这部分。(除了这个:为什么要反转输出ls
并获取最后一个条目?为什么不是来自非反转输出的第一个条目?你grep
支持-m 1
吗?)grep
cd
如果失败,不应调用。你应该双引号变量,除非你知道你不需要。:) 不引用
$ssh_key_file
或$1
可能会打开一罐……惊喜。$2
在您的代码中有些不同。从上下文中我看到它应该在本地扩展并将结果传递给远程 shell。到达远程 shell 的任何内容都将被解析。我猜你不希望本地扩展的结果$2
在远程端进行变量扩展(或者你呢?)。$2
在您的原始脚本中,远程 shell 会在双引号内的单引号中看到局部扩展,外部的很重要。所以你应该在本地扩展$2
在单引号中出现在远程 shell 中。但是你有文字单引号嵌入这个字符串作为grep
模式的一部分,它们应该是双引号。这导致引用狂潮,这很棘手。您传递给远程 shell 的仍然是一个将被解析的字符串, (local) 的某些值
$2
将破坏代码。代码注入是可能的。这是一个常见问题,其中取决于变量的命令作为要解析的字符串传递,很难对此进行清理。我希望你能完全控制本地$2
. 如果不是,那就是一个漏洞:控制它的任何人都能够以ubuntu
远程主机上的用户身份运行任意命令。例如,如果您在$2
扩展到"& rm -rf ~/ & "
(双引号属于此处的变量)时运行您的原始代码,您会感到不愉快(所以不要这样做)。以下代码段完全未经测试。您的代码看起来非常具体,因此很难对其进行测试。
笔记:
$2
需要到达远程端的本地扩展和单引号,我决定对整个命令进行双引号。将它的某些部分放在单引号中可能会减少引用(和转义)的狂热,但它不一定会使命令不那么神秘,因为很难发现以哪种方式引用了哪个部分。$2
仍然使代码注入成为可能。验收后说明
OP 报告以下代码有效:
此代码以与我上面的代码相同的方式解决了主要问题。就语法(?)而言,变化可能很重要,但我认为它们相对于主要问题而言是次要的。