linux - 在 bash 脚本中执行 `sh -c`
问题描述
我有一个test.sh
将bash命令作为参数的文件,它执行一些逻辑,即设置和检查一些环境变量,然后执行该输入命令。
#!/bin/bash
#Some other logic here
echo "Run command: $@"
eval "$@"
当我运行它时,这是输出
% ./test.sh echo "ok"
Run command: echo ok
ok
但问题是,当我通过类似的东西时sh -c 'echo "ok"'
,我没有得到输出。
% ./test.sh sh -c 'echo "ok"'
Run command: sh -c echo "ok"
%
所以我尝试用 更改eval
,exec
尝试$@
直接执行(不使用eval
or exec
),甚至尝试执行它并将输出保存到变量中,仍然没有用。
有没有办法以这种格式运行传递的命令并获取我们的输入?
用例:该脚本用作 docker 容器的入口点,它从 docker CMD 接收参数并执行这些参数以运行容器。
作为快速修复,我可以删除sh -c
并在没有它的情况下传递命令,但我想让脚本可重用而不是更改命令。
解决方案
TL;博士:
这是一个典型的用例(在运行复合命令之前在 Docker 入口点脚本中执行一些业务逻辑,在命令行中给出),推荐的脚本最后一行是:
exec "$@"
细节
为了进一步解释这一行,一些评论和超链接:
根据Bash 用户手册,
exec
它是一个 POSIX shell 内置,它在不创建新进程的情况下替换 shell [使用提供的命令]。因此,
exec
在 Docker 入口点上下文中使用这样的方法很重要,因为它确保CMD
执行的程序仍然具有 PID 1 并且可以直接处理信号,包括docker stop
(另请参见其他 SO 答案:加速 docker-compose关机)。双引号 ( ) 对于避免分词
"$@"
也很重要(即确保每个位置参数按原样传递,即使它包含空格)。参见例如:#!/usr/bin/env bash printargs () { for arg; do echo "$arg"; done; } test0 () { echo "test0:" printargs $@ } test1 () { echo "test1:" printargs "$@" } test0 /bin/sh -c 'echo "ok"' echo test1 /bin/sh -c 'echo "ok"'
test0: /bin/sh -c echo "ok" test1: /bin/sh -c echo "ok"
最后
eval
是一个强大的 bash 内置函数,它 (1) 您的用例不需要,(2) 实际上不建议在一般情况下使用,特别是出于安全原因。例如,如果字符串参数eval
依赖于一些用户提供的输入......有关此问题的详细信息,请参阅例如https://mywiki.wooledge.org/BashFAQ/048(它回顾了一些想要使用此内置函数的情况,通常是命令eval "$(ssh-agent -s)"
)。
推荐阅读
- javascript - 如果用户不在页面上,html5 geolocation.watchposition 会起作用吗?
- python - Azure Python SDK - 与 Azure AD 交互
- google-apps-script - 如何将添加到 Google 表格单元格中的图像保存到 Google 云端硬盘?
- node.js - 如何在 Typescript 中下载文件(从 URL)
- c++ - C++ 重载/匹配 N 个嵌套模板
- shortest-path - 对于无向边加权图,如何找到从顶点 v 到顶点 w 的最短路径?
- spring-webflux - 使用反应堆通量和 openpdf 创建 pdf
- database-design - 多对多关系中的重复主键
- c# - AspNet.Security.Oauth.Spotify HttpContext.GetTokenAsync("spotify", "access_token") 第二次登录后返回空令牌+
- symfony - 向 Doctrine 添加额外的外键约束