使用模式在 shell 脚本中使用 wget

使用模式在 shell 脚本中使用 wget

因此,我目前正在尝试设置一个使用 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/"

我在这里做了一些更改。您已将 分配$3OPT2,然后循环遍历所有参数(实际上,这就是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|

每个论点都完美地保存了下来。

相关内容