我目前正在尝试在 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.txt
和file.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 陷阱 1:
for 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
)。