【问题标题】:Problem with run bash script using cat output ( extra quotes )使用 cat 输出运行 bash 脚本的问题(额外引号)
【发布时间】:2021-10-06 05:47:45
【问题描述】:

我的 apache 目录中有一个 bash 脚本,用于下载一些图片并对其进行优化。

我的脚本路径在:/var/www/site/storage/optimazer/photo_optimazer.sh

此脚本从txt 文件中获取一些命令并将其传递给wget

#!/usr/bin/env bash
..
THREAD="$(cat ${THREAD_FILE})";
$(command -v wget) $THREAD
...

${THREAD_FILE}的内容:

$ cat "${THREAD_FILE}"
--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" -np -r -l 1 -A "jpg" --ignore-case -P /var/www/optimazer/public/optimazed -x http://example.com

我尝试使用在 /usr/local/bin/optimaze.sh 创建的另一个 bash 来执行此 bash

我不得不这样做,因为它会与系统服务一起运行。

这是/usr/local/bin/optimaze.sh的内容

#!/usr/bin/env bash

cd /var/www/site/storage/optimazer/
$(command -v bash) photo_optimazer.sh

现在,当我执行 optimaze.sh 时,它会在我的 ${THREAD} 内容中添加一些额外的引号并破坏脚本,我得到了一些类似这样的错误:

--2021-07-30 12:56:59--  http://(windows/
Resolving (windows ((windows)... failed: Name or service not known.
wget: unable to resolve host address ‘(windows’
--2021-07-30 12:56:59--  http://nt/
Resolving nt (nt)... failed: Name or service not known.
wget: unable to resolve host address ‘nt’
--2021-07-30 12:56:59--  http://10.0;/
Resolving 10.0; (10.0;)... failed: Name or service not known.
wget: unable to resolve host address ‘10.0;’
--2021-07-30 12:56:59--  http://win64;/
Resolving win64; (win64;)... failed: Name or service not known.
wget: unable to resolve host address ‘win64;’
--2021-07-30 12:56:59--  http://x64;/
Resolving x64; (x64;)... failed: Name or service not known.
wget: unable to resolve host address ‘x64;’
--2021-07-30 12:56:59--  ftp://rv/90.0)
           => ‘/var/www/scraper/public/***/3/rv/.listing’
Resolving rv (rv)... failed: Name or service not known.
wget: unable to resolve host address ‘rv’
--2021-07-30 12:56:59--  http://gecko/20100101
Resolving gecko (gecko)... failed: Name or service not known.
wget: unable to resolve host address ‘gecko’
--2021-07-30 12:56:59--  http://firefox/90.0%22
Resolving firefox (firefox)... failed: Name or service not known.
wget: unable to resolve host address ‘firefox’

我在 photo_optimazer.sh 中尝试set -ex 看看发生了什么

 wget '--user-agent="Mozilla/5.0' '(Windows' NT '10.0;' 'Win64;' 'x64;' 'rv:90.0)' Gecko/20100101 'Firefox/90.0"' -np -A '"jpg,png"' --ignore-case --ignore-length -P /example/path -x http://example.com

它在我的${THREAD} 输出中添加了单引号,我不知道为什么!

我用GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

【问题讨论】:

  • 这与BashFAQ #50 中描述的问题非常相似。
  • 顺便说一句,你到底为什么要使用$(command -v wget) 而不仅仅是wget?它速度较慢(所有命令替换都需要分叉一个子进程),并且没有任何好处(事实上,它停止 shell 无法记录并稍后重用 wget 的位置,因为它使查找发生在子shell中,所以一旦子shell退出,shell的内存状态就会全部丢失)。
  • 顺便说一句,set -e 不一定是个好主意。我强烈建议您完成BashFAQ #105 中的练习,如果不阅读上面的寓言的话。
  • thisthis 的答案可能会有所帮助。 (但如果可能,使用更易于解析的格式会更好。)(并避免涉及eval 的任何事情——那样会带来疯狂和奇怪的错误。)
  • 对——如果 OP 不接受描述更好的参数列表存储格式的答案,那么他们的问题归结为按字面意思解析这些引号,这会使问题与以上。

标签: linux bash shell unix centos


【解决方案1】:

如果您的参数不能包含换行符,请考虑将THREAD_FILE(最好全小写,如thread_file,以避开reserved all-caps namespace)改为每行包含一个参数,没有任何shell语法

--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0
-np
-r
-l
1
-A
jpg
--ignore-case
-P
/var/www/optimazer/public/optimazed
-x
http://example.com

完成此操作后,您可以使用(在 bash 4.0 或更高版本中)readarraymapfile 将该文件的每一行读入一个新的数组条目:

readarray -t wget_args <"$thread_file"

...然后将该数组展开到您的 wget 命令行:

wget "${wget_args[@]}"

关于上述“保留的全大写命名空间”声明的注释:POSIX 标准仅严格要求 POSIX 指定的工具仅对修改这些工具行为的环境变量使用全大写名称。然而:

  • 当环境变量和shell变量同名时,对shell变量的任何改动也会隐式修改环境变量
  • 将 POSIX 工具定义为仅使用全大写变量的目的是使具有至少一个小写变量的变量名称对应用程序使用安全

当全大写变量用于应用程序定义的目的时,这样做会放弃 POSIX 对内置工具的限制。

【讨论】:

    【解决方案2】:

    对于这种特殊情况,一个想法是将每一行提供给xargs

    对于示例数据,我将 OP 的 $THREAD_FILE 翻倍:

    $ cat tfile
    --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" -np -r -l 1 -A "jpg" --ignore-case -P /var/www/optimazer/public/optimazed -x http://example.com
    --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0" -np -r -l 1 -A "jpg" --ignore-case -P /var/www/optimazer/public/optimazed -x http://example.com
    

    第一次通过xargs

    cat tfile | xargs -r wget
    

    或者我们可以通过将文件直接提供给xargs来消除不必要的cat

    xargs -r -a tfile wget
    

    KamilCuk 的评论/建议的一些变化:

    xargs -r < tfile wget
    xargs -r wget < tfile
    < tfile xargs -r wget
    

    如果我们正在处理一个变量(如 OP 示例):

    thread=$(head -1 tfile)
    xargs -r wget <<< "${thread}"
    

    并扩展&lt;&lt;&lt; "${thread}" 示例...在循环中使用它(例如,需要对多行输入文件中的每一行执行额外的处理):

    while read -r thread
    do
        xargs -r wget <<< "${thread}"
    done < tfile
    

    所有这些都会为处理的每一行生成以下内容:

    --2021-07-31 13:50:41--  http://example.com/
    Resolving example.com (example.com)... 93.184.216.34, 2606:2800:220:1:248:1893:25c8:1946
    Connecting to example.com (example.com)|93.184.216.34|:80... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 1256 (1.2K) [text/html]
    Saving to: ‘/var/www/optimazer/public/optimazed/example.com/index.html.tmp’
    
    example.com/index.html.tmp               100%[================================================================================>]   1.23K  --.-KB/s    in 0.001s
    
    2021-07-31 13:50:41 (1.25 MB/s) - ‘/var/www/optimazer/public/optimazed/example.com/index.html.tmp’ saved [1256/1256]
    
    Removing /var/www/optimazer/public/optimazed/example.com/index.html.tmp since it should be rejected.
    

    【讨论】:

    • xargs -r -a tfile wget 只是xargs -r &lt; tfile wget-a 选项适用于您无法生成 shell 为您执行 &lt; 重定向的情况。
    • hmmm,之前没见过那个,虽然我理解了...&lt; tfile,在命令的中间,触发了我的WTF? 警报:-)我会把它添加到答案中,谢谢
    • 你可以把它放在任何地方,甚至在开始时。 &lt; file cmd argcmd &lt; file argcmd arg &lt; file 相同。我喜欢它作为猫的替代品,即代替cat file | cmd&lt; file cmd
    • 很公平......我刚刚确认xargs -r wget &lt; tfile 也有效
    • stackoverflow.com/questions/26067249/… 中已经教授了这项技术——是否有理由添加新答案而不是重复关闭问题?
    猜你喜欢
    • 2012-10-08
    • 1970-01-01
    • 2020-08-14
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    相关资源
    最近更新 更多