Bash命令将无法在Jupyter Notebook中执行

时间:2019-02-18 12:49:53

标签: python bash jupyter-notebook

我正在尝试从Jupyter Notebook内部执行Bash命令,该命令将随机数写入某些文件。我要发出的命令是

echo $(( RANDOM )) &> {output_files[i]}

其中output_files是输出文件名的Python列表。我不知道如何将Python变量output_files[i]成功地放入Bash命令中,因此我将整个命令创建为字符串,然后尝试通过Notebook执行该命令:

# Create a list of 5 filenames
output_files = [os.path.join(os.getcwd(), 'random-%s.txt' % i) for i in range (5)]

# Write random number to each file
for i in range (5):
    command = "echo $(( RANDOM )) &> " + output_files[i]
    print(command)
    !{command}

当我尝试此操作时,将创建文件./random-0.txt等,但是没有写入任何数字-它们为空。但是,当我直接在终端中运行创建的命令时,它的工作原理与预期的完全一样。创建文件并每个文件包含一个随机数。 print(command)行产生

echo $(( RANDOM )) &> /filepath/random-0.txt
0
echo $(( RANDOM )) &> /filepath/random-1.txt
echo $(( RANDOM )) &> /filepath/random-2.txt
echo $(( RANDOM )) &> /filepath/random-3.txt
echo $(( RANDOM )) &> /filepath/random-4.txt

对该问题进行网络搜索会给Stack Overflow和博客上的几个类似问题带来成功,但所有结果都是“ Windows上不存在Bash命令”或“您可以使用'!”。在Jupyter Notebook中执行Bash命令!”没有关于它如何工作的更多信息,以便我可以调试这样的问题。

我如何进行这项工作?

3 个答案:

答案 0 :(得分:3)

为什么python本身没有全部内容?使用random函数的randint()模块来生成您的号码。定义您选择的范围,并将其包括在(..)

import os
import random
output_files = [os.path.join(os.getcwd(), 'random-%s.txt' % i) for i in range (5)]
for of in output_files:
    with open(of, "w") as text_file:
        text_file.write(str(random.randint(99,1000)))

答案 1 :(得分:2)

您好,欢迎来到Stack Overflow,

据我所知,您的问题不是由用!执行bash命令引起的,而是因为您没有用其实际内容“替换” output_files[i]。 当您运行循环

# Write random number to each file
for i in range (5):
    command = "echo $(( RANDOM )) &> {output_files[i]}"

在每次迭代中,command将是文字字符串"echo $(( RANDOM )) &> {output_files[i]}"。就像您在第一行中所做的那样,应该使用字符串替换将占位符替换为output_files[i]的内容:

# Write random number to each file
for i in range (5):
    command = ("echo $(( RANDOM )) &> {%s}"%output_files[i])

要调试此类问题,通常是检查相关变量的值的好开始。最简单的方法是添加print (x)行,其中x是要检查其内容的变量。

答案 2 :(得分:2)

针对这里的答案之一,让我展示如何使用subprocess.check_call()来做到这一点。

如果要在subprocess中使用shell重定向,则必须具有shell:

for i in range(5):
    subprocess.check_call('echo "$RANDOM" >random-{}.txt'.format(i), shell=True)

您可以从表面上尝试摆脱shell=True ...,但是echo$RANDOM也是Shell的功能。

一个纯Bash解决方案就是

!for i in {0..4}; do printf "%s\n" "$RANDOM" >random-"$i".txt; done

(顺便说一句,$((RANDOM))中的数字上下文没有错,但完全是多余的。)

您可以使用!将Python表达式插入{...}命令行中。例如,以下内容也适用:

!{';'.join(['echo $RANDOM >random-{}.txt'.format(i) for i in range(5)])}

在iPython中,我可以使用您尝试过的结构产生期望的结果:

in [15]: for i in range(2):
    ...:     c='echo $RANDOM >random-{}.txt'.format(i)
    ...:     !{c}
    ...:

in [16]: !tail random-*.txt
==> random-0.txt <==
15637

==> random-1.txt <==
32475

如果Jupyter使用的是iPython内核,我想这也应该对您有用。

还请注意我是如何使用普通的旧>重定向而不是&>的-真的 really really 并没有理智的理由想要错误消息重定向到文件;如果无法创建文件,则您完全不知道什么失败或为什么失败,甚至失败。 (实际上,我怀疑这确实是您遇到问题的原因。权限被拒绝?磁盘已满?我们不知道。)

不过,我建议您使用Python执行此简单任务。运行子进程来执行某些在Python本身中相对容易实现的操作,效率低下,笨拙且有些脆弱。