我有一个最小的无头 *nix不具有任何用于下载文件的命令行实用程序(例如,没有 curl、wget 等)。我只有 bash。
我怎样才能下载文件?
理想情况下,我想要一个能够在广泛的 *nix 上工作的解决方案。
答案1
如果您有 bash 2.04 或更高版本并/dev/tcp
启用了伪设备,则可以从 bash 本身下载文件。
将以下代码直接粘贴到 bash shell 中(无需将代码保存到文件中执行):
function __wget() {
: ${DEBUG:=0}
local URL=$1
local tag="Connection: close"
local mark=0
if [ -z "${URL}" ]; then
printf "Usage: %s \"URL\" [e.g.: %s http://www.google.com/]" \
"${FUNCNAME[0]}" "${FUNCNAME[0]}"
return 1;
fi
read proto server path <<<$(echo ${URL//// })
DOC=/${path// //}
HOST=${server//:*}
PORT=${server//*:}
[[ x"${HOST}" == x"${PORT}" ]] && PORT=80
[[ $DEBUG -eq 1 ]] && echo "HOST=$HOST"
[[ $DEBUG -eq 1 ]] && echo "PORT=$PORT"
[[ $DEBUG -eq 1 ]] && echo "DOC =$DOC"
exec 3<>/dev/tcp/${HOST}/$PORT
echo -en "GET ${DOC} HTTP/1.1\r\nHost: ${HOST}\r\n${tag}\r\n\r\n" >&3
while read line; do
[[ $mark -eq 1 ]] && echo $line
if [[ "${line}" =~ "${tag}" ]]; then
mark=1
fi
done <&3
exec 3>&-
}
然后您可以从 shell 执行它,如下所示:
__wget http://example.iana.org/
来源:莫雷基的回答通过 cygwin 命令行升级和安装包?
更新: 正如评论中提到的,上面概述的方法很简单:
- 该
read
意志会丢弃反斜杠和前导空格。 - Bash 不能很好地处理 NUL 字节,因此二进制文件被淘汰。
- 不加引号
$line
将导致全局。
答案2
使用山猫。
对于大多数 Unix/Linux 来说这很常见。
lynx -dump http://www.google.com
-dump:将第一个文件转储到标准输出并退出
man lynx
或者网猫:
/usr/bin/printf 'GET / \n' | nc www.google.com 80
或远程登录:
(echo 'GET /'; echo ""; sleep 1; ) | telnet www.google.com 80
答案3
改编自克里斯·斯诺的回答。这也可以处理二进制文件。
function __curl() {
read -r proto server path <<<"$(printf '%s' "${1//// }")"
if [ "$proto" != "http:" ]; then
printf >&2 "sorry, %s supports only http\n" "${FUNCNAME[0]}"
return 1
fi
DOC=/${path// //}
HOST=${server//:*}
PORT=${server//*:}
[ "${HOST}" = "${PORT}" ] && PORT=80
exec 3<>"/dev/tcp/${HOST}/$PORT"
printf 'GET %s HTTP/1.0\r\nHost: %s\r\n\r\n' "${DOC}" "${HOST}" >&3
(while read -r line; do
[ "$line" = $'\r' ] && break
done && cat) <&3
exec 3>&-
}
- 我
break && cat
要出去read
。 - 我使用 HTTP 1.0,因此无需等待/发送连接:关闭。
您可以像这样测试二进制文件:
$ __curl http://www.google.com/favicon.ico > mine.ico
$ curl http://www.google.com/favicon.ico > theirs.ico
$ md5sum mine.ico theirs.ico
f3418a443e7d841097c714d69ec4bcb8 mine.ico
f3418a443e7d841097c714d69ec4bcb8 theirs.ico
答案4
使用本地计算机上的 SSH 上传
“最小的无头 *nix”盒子意味着你可能通过 SSH 连接到它。所以你也可以使用SSH上传到它。这在功能上相当于下载(软件包等)除了当然,当您希望将下载命令包含在无头服务器上的脚本中时。
如图所示这个答案,您将在您的当地的将文件放置在远程无头服务器上的机器:
wget -O - http://example.com/file.zip | ssh user@host 'cat >/path/to/file.zip'
从第三台机器通过 SSH 上传速度更快
与下载相比,上述解决方案的缺点是传输速度较低,因为与本地计算机的连接通常比无头服务器和其他服务器之间的连接具有更少的带宽。
要解决这个问题,您当然可以在另一台具有适当带宽的服务器上执行上述命令。为了使这更舒适(避免在第三台机器上手动登录),这里有一个要执行的命令在您的本地计算机上。
为了安全起见,请复制并粘贴该命令包括前导空格字符 ' '
。原因请看下面的解释。
ssh user@intermediate-host "sshpass -f <(printf '%s\n' yourpassword) \
ssh -T -e none \
-o StrictHostKeyChecking=no \
< <(wget -O - http://example.com/input-file.zip) \
user@target-host \
'cat >/path/to/output-file.zip' \
"
说明:
该命令将 ssh 到您的第三台机器
intermediate-host
,开始通过 SSH 下载文件到那里,并开始通过 SSHwget
上传到那里。target-host
下载和上传使用您的带宽intermediate-host
并且同时发生(由于 Bash 管道等效),因此进度会很快。使用此功能时,您必须将两个服务器登录名 (
user@*-host
)、目标主机密码 (yourpassword
)、下载 URL (http://example.com/…
) 和目标主机上的输出路径 (/path/to/output-file.zip
) 替换为适当的自己的值。有关
-T -e none
使用 SSH 传输文件时的选项,请参阅这些详细的解释。此命令适用于无法使用 SSH 公钥身份验证机制的情况 - 某些共享托管提供商仍然会发生这种情况,尤其是东道主欧洲。为了仍然自动化该过程,我们依赖于
sshpass
能够在命令中提供密码。它需要sshpass
安装在您的中间主机上(sudo apt-get install sshpass
在 Ubuntu 下)。我们尝试
sshpass
以安全的方式使用,但它仍然不会像 SSH 公钥机制那样安全(说man sshpass
)。特别是,我们不是以命令行参数的形式提供 SSH 密码,而是通过文件提供,该文件由 bash 进程替换来替换,以确保它永远不会存在于磁盘上。这printf
是一个内置的 bash,确保这部分代码不会在ps
输出中作为单独的命令弹出,因为这会暴露密码 [来源]。我思考这种使用与 中推荐的变体sshpass
一样安全,因为 bash无论如何都会在内部将其映射到这样的文件描述符。并且不使用临时文件[sshpass -d<file-descriptor>
man sshpass
/dev/fd/*
来源]。但不能保证,也许我忽略了一些事情。同样,为了确保
sshpass
使用安全,我们需要防止该命令被记录到本地计算机上的 bash 历史记录中。为此,整个命令前面都会添加一个空格字符,从而达到此效果。该
-o StrictHostKeyChecking=no
部分可防止命令在从未连接到目标主机的情况下失败。 (通常情况下,SSH 会等待用户输入来确认连接尝试。无论如何,我们都会让它继续进行,以免中间主机上出现无限期挂起的命令。)sshpass
期望ssh
orscp
命令作为其最后一个参数。所以我们必须重写典型的wget -O - … | ssh …
命令重写为没有 bash 管道的形式,如所解释的这里。