在下面的位置后卷取远程文件名

当使用 curl 下载文件时,如何跟踪链接位置并将其用于输出文件名(在事先不知道远程文件名的情况下) ?

例如,如果单击下面的链接,您将下载一个名为“ pythonComplete.vim”的文件但是使用 curl 的-O 和-L 选项,文件名只是原始的 remote-name,一个笨拙的“ download _ script.php?Src _ id = 10872”

curl -O -L http://www.vim.org/scripts/download_script.php?src_id=10872

为了下载具有正确文件名的文件,你必须事先知道文件的名称:

curl -o pythoncomplete.vim -L http://www.vim.org/scripts/download_script.php?src_id=10872

如果您可以下载文件而不事先知道文件的名称,那就太好了。如果不知道,是否有其他方法可以通过命令行快速下拉重定向文件?

81087 次浏览

If you have a recent version of curl (7.21.2 or later), see @jmanning2k's answer.

I you have an older version of curl (like 7.19.7 which came with Snow Leopard), do two requests: a HEAD to get the file name from response header, then a GET:

url="http://www.vim.org/scripts/download_script.php?src_id=10872"
filename=$(curl -sI  $url | grep -o -E 'filename=.*$' | sed -e 's/filename=//')
curl -o $filename -L $url

The remote side sends the filename using the Content-Disposition header.

curl 7.21.2 or newer does this automatically if you specify --remote-header-name / -J.

curl -O -J -L $url

The expanded version of the arguments would be:

curl --remote-name --remote-header-name --location $url

I wanted to comment to jmanning2k's answer but as a new user I can't, so I tried to edit his post which is allowed but the edit was rejected saying it was supposed to be a comment. sigh

Anyway, see this as a comment to his answer thanks.

This seems to only work if the header looks like filename=pythoncomplete.vim as in the example, but some sites send a header that looks like filename*=UTF-8' 'filename.zip' that one isn't recognized by curl 7.28.0

Please note that certain malconfigured webservers will serve the name using "Filename" as key, where RFC2183 specifies it should be "filename". curl only handles the latter case.

I wanted a solution that worked on both older and newer Macs, and the legacy code David provided for Snow Leopard did not behave well under Mavericks. Here's a function I created based on David's code:

function getUriFilename() {
header="$(curl -sI "$1" | tr -d '\r')"


filename="$(echo "$header" | grep -o -E 'filename=.*$')"
if [[ -n "$filename" ]]; then
echo "${filename#filename=}"
return
fi


filename="$(echo "$header" | grep -o -E 'Location:.*$')"
if [[ -n "$filename" ]]; then
basename "${filename#Location\:}"
return
fi


return 1
}

With this defined, you can run:

url="http://www.vim.org/scripts/download_script.php?src_id=10872"
filename="$(getUriFilename $url)"
curl -L $url -o "$filename"

An example using the answer above for Apache Archiva artifact repository to pull latest version. The curl returns the Location line and the filename is at the end of the line. Need to remove the CR at end of file name.

url="http://archiva:8080/restServices/archivaServices/searchService/artifact?g=com.imgur.backup&a=snapshot-s3-util&v=LATEST"
filename=$(curl --silent -sI -u user:password $url | grep Location | awk -F\/ '{print $NF}' | sed 's/\r$//')
curl --silent -o $filename -L -u user:password $url

If you can use wget instead of curl:

wget --content-disposition $url

I had the same Problem like John Cooper. I got no filename but a Location File name back. His answer also worked but are 2 commands. This oneliner worked for me....

url="https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=de";url=$(curl -L --head -w '%{url_effective}' $url 2>/dev/null | tail -n1) ; curl -O $url

Stolen and added some stuff from https://unix.stackexchange.com/questions/126252/resolve-filename-from-a-remote-url-without-downloading-a-file

Using the solution proposed above, I wrote this helper function curl2file.

[UPDATED]

function curl2file() {
url=$1
url=$(curl -o /dev/null -L --head -w '%{url_effective}' $url 2>/dev/null | tail -n1) ; curl -O $url
}

Usage:

curl2file https://cloud.tsinghua.edu.cn/f/4666d28af98a4e63afb5/?dl=1

instead of applying grep and other Unix-Fu operations, curl ships with a builtin "Write Out" option variable[1] specifically for such a case, e.g.

$ curl -OJsL "http://www.vim.org/scripts/download_script.php?src_id=10872" -w "%{filename_effective}"
pythoncomplete.vim

[1] https://everything.curl.dev/usingcurl/verbose/writeout#available-write-out-variables