这个脚本的名字是hello
for i in $(ls $*);do
x=$(echo $(basename $i".md"));
pandoc $i -t "latex" -o $x.pdf;
done
当我写这个的时候
$ ./hello *bye.md
这个错误
ls: cannot access 'test': No such file or directory
ls: cannot access 'de': No such file or directory
ls: cannot access 'bye.md': No such file or directory
basename: extra operand ‘bye.md’
Try 'basename --help' for more information.
./hello: 2: ./hello: pandoc: not found
basename: extra operand ‘.md’
Try 'basename --help' for more information.
./hello: 2: ./hello: pandoc: not found
我不明白为什么我的脚本 hello 不能正常工作?
并且以下命令不会在正确的目录中创建 pdf:
$ ./hello */test.md
答案1
您可以使用命令调试脚本set -x
,该命令准确显示正在执行哪些命令(您可以使用 禁用该模式set +x
)。您可能会从中看到,您正在对不存在的文件运行循环,然后运行basename
不正确。
此外:
不解析 ls 的输出。
for i in "$@"; do
会很适合你的。basename
需要扩展名作为单独的参数,因此您应该编写basename $i ".md"
:您缺少保存文件名的变量和扩展名之间的空格。如果变量包含空格,则应该引用它们,这样您实际上想要
basename "$i" .md
并且pandoc "$i" -t "latex" -o "$x".pdf
这
echo
是多余的,你不妨使用x=$(basename "$i" .md)
答案2
该脚本存在许多问题,对于经验丰富的脚本编写者来说,这些问题是显而易见的。但你的问题是“我如何调试”。
首先:以清晰易读的形式编写脚本,而不是单行文字:
#!/bin/bash
for i in $(ls $*) ; do
x=$(echo $(basename $i".md"))
pandoc $i -t "latex" -o $x.pdf
done
您会注意到我添加了一个#!/bin/bash
.这迫使bash
脚本使用。那么,如何调试呢?
$i
是循环变量;当你经历这个循环时,它包含你的想法吗?回声会清楚地表明这一点。您可以对 $x 执行相同的操作:
#!/bin/bash
for i in $(ls $*) ; do
echo "LOOP VARIABLE $i"
x=$(echo $(basename $i".md"))
echo "AND X IS $x"
pandoc $i -t "latex" -o $x.pdf
done
这是调试的基本方法。
那么,现在回到您的脚本、输出等。test de bye.md
您的目录中有一个名为“”的文件,我对吗?
好的。从头开始(实际上:缺少的@!
是这一点,但那是挑剔)。永远不要解析ls
.我为此被责骂过很多次这里你可以阅读原因。
$*
您可能还对和之间的区别感兴趣$@
,我将把它留给您的谷歌技能。
建筑x=$(echo $(basename $i".md"))
很奇怪。我什至不明白你想在这里完成什么,特别是如果你已经在.md
文件名末尾调用脚本。
您可能还想引用其中包含空格的参数。例如:如果 $i 将包含test de bye.md
,ls $i
将调用带有 3 个参数的 `ls:
- 测试
- 德
- 再见.md
whilels "$i"
会ls
用一个参数进行校准:
- 测试再见.md
这将会产生完全不同的结果。
另一个问题:您确定pandoc
您的系统上安装了该软件吗?错误消息表明事实并非如此。验证与which pandoc
.
对于那些学过 Fortran 的人(我已经这么老了!),i 是一个整数。但您也可以使用描述性名称,这将使以后的脚本维护更加容易。
所以,这将使脚本:
#!/bin/bash
for infile in "$@" ; do
outfile=${infile%.md}.pdf
pandoc "$infile" -t latex -o "$outfile"
done
或类似的东西。
答案3
你的循环:
for i in $(ls $*);do
x=$(echo $(basename $i".md"));
pandoc $i -t "latex" -o $x.pdf;
done
更正版本:
#!/bin/sh
for pathname do
pandoc "$pathname" -t "latex" -o "$( basename "$pathname" .md ).pdf"
done
笔记:
要迭代命令行参数,只需执行
for variable do ...; done
.$*
是与 的第一个字符连接的位置参数$IFS
,您很少需要使用它。由于它没有被引用,结果将被空格分割,这是您收到的一些错误消息(来自 的错误消息ls
)的原因。分裂的单词也会经历文件名通配。的输出ls
严格用于看着at (而且没有理由列出文件名,因为它们是在命令行上交给您的)。$(echo $(some-utility))
更正确地写为$(some-utility)
.不需要echo
,会介绍有趣的在某些情况下,当给定的实用程序输出反斜杠等时会产生影响。此外,输出上也会发生分词和文件名通配。我选择不使用中间变量。无论如何,你只需要使用它一次。我还猜测您想删除
.md
文件名后缀,因此我为循环使用了更具描述性的变量名称。请注意,您似乎正在写入当前目录中的文件,即使您可能获得可能包含子目录的路径名,例如somedir/file.md
.
写入原始文件所在目录中的文件的变体.md
:
#!/bin/sh
for pathname do
pandoc "$pathname" -t "latex" -o "${pathname%.md}.pdf"
done
答案4
使用for
循环程序输出可能是一项艰苦的工作。循环while
往往更容易。另外,我不认为 2 号线正在做你认为的那样。试试这个:
ls $* | while read infilename; do
outfilename=$(echo $infilename | sed 's/.md/.pdf/')
pandoc $infilename -t "latex" -o ${outfilename}.pdf;
done