如何调试我的脚本?

如何调试我的脚本?

这个脚本的名字是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

相关内容