无法确定 bash 脚本中带空格的文件名的引号应该放在哪里

无法确定 bash 脚本中带空格的文件名的引号应该放在哪里

我目前正在尝试在 python 虚拟环境中使用 html2txt 将一堆 html 文件批量转换为 txt 文件。我的脚本目前如下:

#!/usr/bin/bash

NAME=""
source ~/pythonenvs/env_tomboyconversion/bin/activate

for i in $(ls *.html); do
    NAME=$(basename -s .html $i)
    html2text $i > "$NAME.txt"
done

deactivate

每当我运行脚本时,我都会得到多个空文本文件,很明显原始文件名是用空格分隔的。例如,如果我有一个文件original file.html,它将导致original.txtfile.txt我遇到的问题是我不知道在哪里应用引号以防止文件名被空格分割。我尝试了上述方法,以及在表达式$i周围加上$(basename -s .html $i), 以及上述方法的各种组合,但文件名总是被分割。我怎样才能让文件名不再被空格分割?

答案1

这是改进的循环:

shopt -s nullglob
for i in ./*.html; do
    name="$(basename -s .html "$i")"
    html2text "$i" > "$name.txt"
done

改进:

  • Bash 陷阱 1for i in $(ls *.html); do存在缺陷。问题之一:

    如果文件名包含空格,则会进行 WordSplitting。

    但还有更多。您无法通过引用来修复它。对于您来说,ls根本没有理由调用。*.html直接使用是正确的方法。

  • 正确的双引号. 使用双引号括住变量替换和命令替换。在此特定行中

    name="$(basename -s .html "$i")"
    

    引号是嵌套的(见,怪癖 2)。这里外层是可选的,因为变量赋值的形式

    foo=$(command_that_can_output_spaces_or_such)
    

    无论如何都会起作用,但这仅在以这种简单方式分配时才有效。通常,您确实需要双引号。例如,您可能根本$(…)不使用变量:name

    html2text "$i" > "$(basename -s .html "$i").txt"
    

    在这种情况下,您不应省略任何引号。

  • NAME更改为name。请参阅这个答案

    由操作系统或者shell启动脚本等引入的环境变量或者shell变量通常都在 中CAPITALS

    为了防止您自己的变量与这些变量冲突,使用小写是一种很好的做法。

  • 每个都$i以 开头./。这可以防止其他工具将其解释为选项(如果变量值恰好以 开头-)。另一种处理方法:--。我想basename明白了--,但我不确定html2text,因此技巧是./

  • shopt -s nullglob当 不匹配时很有用./*.html。通常在这种情况下,模式不会扩展,循环将以$i文字字符串运行一次./*.html。这不是您想要的。shopt -s nullglob允许模式扩展为零,因此如果没有匹配,循环将根本不运行。这是 bashism,它可以在 Bash 中工作,但其他 shell 可能/不会理解它。


你不需要basename删除扩展,shell 可以自行执行此操作:

shopt -s nullglob
for i in ./*.html; do
    html2text "$i" > "${i%.html}.txt"
done

这种方法避免产生额外的进程(basename)。

相关内容