因此,我目前正在尝试设置一个使用 wget 的 shell 脚本,以便从服务器下载大量文件。我使用 -A 'pattern*.extension' 选项仅下载我感兴趣的具有特定模式和扩展名的文件。(此外,还有很多文件我不想浪费 PC 上的空间。)如果我通过命令行执行 wget,一切都会正常工作,它会下载与模式匹配的所有文件。现在,如果我尝试使用与之前完全相同的 wget 命令运行脚本,它会突然显示:“wget:不匹配”。(我应该提到,shell 脚本是由 python 脚本执行的,该脚本提供了从特定子文件夹下载文件的 ID 列表。)但是:如果我打印 shell 脚本执行的确切 wget 行并将其复制并粘贴到命令行中,它会再次起作用。这对我来说毫无意义。
以下是我的 wget 的样子:
wget -r -c -nH -np -nd -e robots=off -P PATH -A 'pattern*.extension' -a logfile.log --progress=bar:force --no-check-certificate https://.../ID/
下面是我的 shell 脚本的基本内容:
#!/usr/bin/tcsh
set ID=$1 #just an ID for subfolders
set OPT2=$3 #additional options that can be passed to wget
set OPT="-r -c -nH -np -nd -e robots=off -P PATH/$ID -A 'pattern*.extension' -a $ID.log"
set OOP="--progress=bar:force --no-check-certificate"
while ($1 != '')
echo "wget $OPT $OOP $OPT2 https://.../$ID/"
wget $OPT $OOP $OPT2 https://.../$ID/
shift
end
输出如下:
wget -r -c -nH -np -nd -e robots=off -P PATH/ID -A 'pattern*.extension' -a ID.log --progress=bar:force --no-check-certificate https://.../ID/
wget: No match.
但是现在,如果我复制脚本所显示的那行代码,它就可以正常工作了!请告诉我。我曾努力尝试修复这个问题,但显然我没能成功。
另外:如果我将 -A 'pattern*.extension' 替换为 -A.extenstion,它会下载所有带有该扩展名的文件。出于某种原因,使用模式时它不起作用。
正如我上面提到的,shell脚本被python脚本调用:
for ID in IDs:
cmd = 'csh PATH/script.csh %s' % (ID)
sub.call( cmd, shell=True )
也许这也有帮助,也许我还应该提到我并不是一个高级程序员。
提前致谢。
答案1
我不熟悉 tcsh,所以 tcsh 中可能有一个很好的解决办法。
话虽如此,我熟悉 bash,并且知道是什么导致了这个问题。请注意此处的引用:
set OPT="-r -c -nH -np -nd -e robots=off -P PATH/$ID -A 'pattern*.extension' -a $ID.log"
有一个外层引号,此外,还有一个内层引号pattern*.expansion
。 假设您使用内层,因为如果您实际在 shell 中输入命令,它看起来就像这样。
其工作方式是,shell 在命令行上执行各种扩展,例如变量扩展、通配符扩展等。因此在如下命令中:
wget $OPT ...
shell 将扩展$OPT
其内容,执行字段拆分,分离出两个单词的内容$OPT
,以及通配符扩展(或通配符),这是命令失败的地方:
> set foo="'*'"
> echo $foo
echo: No match.
> echo "$foo"
'*'
注意引号是如何$foo
避免错误的?但是您不能在脚本中使用引号,因为引号也会阻止字段拆分,并且您依赖于字段拆分,以便$OPT
(-r
、-c
等)中的各种选项作为单独的参数传递给wget
。
以下是带引号和不带引号的差异的演示:
> printf "|%s|\n" "$OPT"
|-r -c -nH -np -nd -e robots=off -P PATH/foo -A 'pattern*.extension' -a foo.log|
> printf "|%s|\n" $OPT
printf: No match.
> printf "|%s|\n" -r -c -nH -np -nd -e robots=off -P PATH/$ID -A 'pattern*.extension' -a $ID.log
|-r|
|-c|
|-nH|
|-np|
|-nd|
|-e|
|robots=off|
|-P|
|PATH/foo|
|-A|
|pattern*.extension|
|-a|
|foo.log|
我想如果你使用以下方法可能会有效:
set OPT="-r -c -nH -np -nd -e robots=off -P PATH/$ID -A pattern*.extension -a $ID.log"
但是,如果您不使用"$OPT"
,并且工作目录中有匹配的文件,则可能会有通配符扩展的风险pattern*.extension
:
> touch pattern-abc.extension
> printf "|%s|\n" $OPT
printf: No match.
> set set OPT="-r -c -nH -np -nd -e robots=off -P PATH/$ID -A pattern*.extension -a $ID.log"
> printf "|%s|\n" $OPT
|-r|
|-c|
|-nH|
|-np|
|-nd|
|-e|
|robots=off|
|-P|
|PATH/foo|
|-A|
|pattern-abc.extension| <---- tcsh expanded pattern*.extension
|-a|
|foo.log|
再说一遍,我对 tcsh 的熟练程度不足以提出一个好的解决方案,但我知道 bash 中一个不错的解决方案:
使用数组来构建命令行。
在 bash 中,你的脚本看起来如下:
#!/bin/bash
ID=$1 #just an ID for subfolders
shift
OPT2=("$@") #additional options that can be passed to wget
OPT=(-r -c -nH -np -nd -e robots=off -P PATH/"$ID" -A 'pattern*.extension' -a "$ID".log)
OOP=(--progress=bar:force --no-check-certificate)
echo wget "${OPT[@]}" "${OOP[@]}" "${OPT2[@]}" "https://.../$ID/"
wget "${OPT[@]}" "${OOP[@]}" "${OPT2[@]}" "https://.../$ID/"
我在这里做了一些更改。您已将 分配$3
给OPT2
,然后循环遍历所有参数(实际上,这就是while ($1 != '') ... shift
要执行的操作),但没有在循环中使用这些参数,这没有意义 - 脚本的第二个参数实际上被忽略,但第三个参数用作选项。鉴于 Python 代码片段,我将假设只有第一个参数是 ID,其余的是 的选项wget
。
现在,使用如下数组:
OPT=(-r -c -nH -np -nd -e robots=off -P PATH/"$ID" -A 'pattern*.extension' -a "$ID".log)
允许我们扩展到数组中的每个单独的单词,同时不冒字段拆分或文件名生成的风险,"${OPT[@]}"
在 bash 中使用:
$ printf "|%s|\n" "${OPT[@]}"
|-r|
|-c|
|-nH|
|-np|
|-nd|
|-e|
|robots=off|
|-P|
|PATH/foo|
|-A|
|pattern*.extension|
|-a|
|foo.log|
每个论点都完美地保存了下来。