以下代码应该为我提供一个"工作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: ./install_programs: /bin/bash^M: bad interpreter: No such file or directory
如果我删除所有内容直到第一个apt-get ..
行,并添加bash扩展名" .sh"
口译员认出来了。
"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
答案 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\r
与if
匹配,或导致您尝试安装名为'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
模块不是输出所必需的,并且确实妨碍了。