使用python csv模块创建安装bash脚本

时间:2014-07-22 23:51:56

标签: python linux bash unix

以下代码应该为我提供一个"工作bash脚本"

box_category=GET_COMBOBOX_value(self,self.combobox_category2,False)
list_path=Data_Location+"/program-data/programs_to_install.csv"
list=csv.reader(open(list_path),delimiter='|')

bash_file=path+"/install_programs"
if os.path.exists(bash_file):
    os.remove(bash_file)

with open(bash_file, "ab") as f:
    bash_list=csv.writer(f,delimiter='|')   
    bash_list.writerow(["#!/bin/bash"])
    bash_list.writerow([" "])
    string="if [ \"$(id -u)\" != \"0\" ]; then echo \"You need root permission for installing programs.\" 1>&2; exit 1; fi"
    print string        
    bash_list.writerow([string])

    for row in list :
        bash_list.writerow(["apt-get --yes install "+row[0]])

time.sleep(0.2)
os.system("chmod a+x '"+bash_file+"'")

初看起来,几乎是"正确地,它生成我这个bash文件:

#!/bin/bash

"if [ ""$(id -u)"" != ""0"" ]; then echo ""You need root permission for installing programs."" 1>&2; exit 1; fi"
apt-get --yes install 0ad
apt-get --yes install audacity
apt-get --yes install banshee
apt-get --yes install barrage
..etc..

但:

  • 当我执行bash文件时,我收到错误bash: ./install_programs: /bin/bash^M: bad interpreter: No such file or directory

如果我删除所有内容直到第一个apt-get ..行,并添加bash扩展名" .sh" 口译员认出来了。

  • csv模块写得不好

"if [ \"$(id -u)\" != \"0\" ]; then echo \"You need root permission for installing programs.\" 1>&2; exit 1; fi"

应该写:

if [ "$(id -u)" != "0" ]; then echo "You need root permission for installing programs." 1>&2; exit 1; fi

  • 我最后一个谜,就是即使我手动修复所有这些东西,一旦我执行脚本它就不会安装任何程序,即使命令是正确的,如果我在一个名词中使用它们也可以工作..

我得到这样的输出:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
E: Unable to locate package 0ad
Reading package lists... Done
Building dependency tree       
Reading state information... Done
E: Unable to locate package audacity
Reading package lists... Done
Building dependency tree       
Reading state information... Done

2 个答案:

答案 0 :(得分:2)

CSV的重点在于逗号分隔值 - 即每行上有多个列,以逗号分隔。这意味着如果您的任何值碰巧有逗号,则必须引用(或转义)该值。而那些引用规则意味着如果你的任何值碰巧有一个引号字符,那么必须引用该值来处理它。所以,而不是:

if [ "$(id -u)" != "0" ]; then echo "You need root permission for installing programs." 1>&2; exit 1; fi

...你最终得到了这个:

"if [ ""$(id -u)"" != ""0"" ]; then echo ""You need root permission for installing programs."" 1>&2; exit 1; fi"

这当然不是有效的bash命令。

简单的解决方案是不使用csv模块;只需将您的行写入文件,而不是试图将每个行转换为一列的列表,以便csv模块写入以获得您想要的行。

with open(bash_file, "a") as f:
    f.write("#!/bin/bash\n")
    f.write(" \n")
    string="if [ \"$(id -u)\" != \"0\" ]; then echo \"You need root permission for installing programs.\" 1>&2; exit 1; fi"
    print string        
    f.write(string + "\n")
    for row in list:
        f.write("apt-get --yes install " + row[0] + "\n")

如果您厌倦了全部输入所有这些显式换行符,可以将write函数包起来:

def writeline(f, line):
    f.write(line + '\n')

然后,你到处都这样做了:

f.write(string + "\n")

...你可以这样做:

writeline(f, string)

这可能是一个好主意;否则,你会忘记" \ n"在一条线上 - 或者更糟糕的是,错误地输入它 - 花一个小时来调试你的代码,无论你多少盯着它看起来都很明显,但仍然没有工作......


此错误:

bash: ./install_programs: /bin/bash^M: bad interpreter: No such file or directory
使用csv模块导致

...

默认的CSV方言使用Windows样式的换行符,即每行以'\r\n'结尾。 (请参阅文档中的Dialect.lineterminator。)但bash需要Unix风格的换行符 - 也就是说,每一行都以'\n'结尾。因此,它将额外的'\r'视为实际行的一部分。所以,在shebang系列中,不是认为你想要'/bin/bash'作为你的翻译,而是认为你想要'/bin/bash\r' - 这是一个完全有效的文件名,但是没有那个名字的文件。


你的最后一个问题很可能是完全相同的问题。一个额外的隐藏'\r'字符可能阻止fi\rif匹配,或导致您尝试安装名为'0ad\r'而非'0ad'的包,等


几个旁注:

  • 永远不要调用变量list;隐藏了您可能想要使用的同名的内置类型/功能。此外,虽然它的出现频率较低,但string是stdlib模块的名称,所以通常也要避免使用它。
  • 如果用单引号而不是双引号来编写字符串文字,则不需要转义其中的每个双引号。或者您可以使用三倍(单引号或双引号)引号,并且您不需要转义任何类型的引号,甚至是换行符:"""if [ "$(id -u)" != "0" ]; then echo "You need root permission for installing programs." 1>&2; exit 1; fi"""

答案 1 :(得分:0)

第一条线索可能在"^M"。这是一个回车符,并被shebang执行机制视为可执行路径的一部分。如果没有适当的清理,请不要在其他环境中使用Windows中创建的文本文件。无论如何,通过使用sh来运行脚本,你克服了这一点。正如@abarnert在他/她的回答中指出的那样,csv模块不是输出所必需的,并且确实妨碍了。