You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Amazon EMR运行自定义脚本遇文件不存在错误求助

问题:AWS EMR中通过script-runner运行Python脚本时出现"No such file or directory"错误

我在AWS EMR中搭建JupyterHub环境,此前按照官方文档操作无异常。希望在集群部署阶段添加步骤批量创建用户,官方提供的示例Bash脚本可通过script-runner.jar成功运行。但替换为自定义的add_users_ERM.sh脚本(实际为Python脚本)后,运行时出现"error=2, No such file or directory"错误,错误日志及脚本内容如下:

错误日志

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/usr/lib/hadoop/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/usr/lib/tez/lib/slf4j-reload4j-1.7.36.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
Exception in thread "main" java.lang.RuntimeException: java.io.IOException: Cannot run program "/mnt/var/lib/hadoop/steps/s-23QLFU7JXPPM7/./add_users_ERM.sh" (in directory "."): error=2, No such file or directory
    at com.amazon.elasticmapreduce.scriptrunner.ProcessRunner.exec(ProcessRunner.java:143)
    at com.amazon.elasticmapreduce.scriptrunner.ScriptRunner.main(ScriptRunner.java:58)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.hadoop.util.RunJar.run(RunJar.java:323)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:236)
Caused by: java.io.IOException: Cannot run program "/mnt/var/lib/hadoop/steps/s-23QLFU7JXPPM7/./add_users_ERM_Linuxx.sh" (in directory "."): error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at com.amazon.elasticmapreduce.scriptrunner.ProcessRunner.exec(ProcessRunner.java:96)
    ... 7 more
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
    ... 8 more

自定义脚本add_users_ERM.sh

#!/opt/conda/bin/python

import os
import subprocess
import traceback
import sys

TOKEN="$(sudo docker exec jupyterhub /opt/conda/bin/jupyterhub token jovyan | tail -1)"

def users_from_text(file):
        
    #Now we have users and their team, we can create a user account and assign them to a team
    for user in file:
                username = user
 
                print(f"Adding {user}")
                cmd = ["sudo", "docker", "exec", "jupyterhub","useradd", "-m" ,"-s" ,"/bin/bash" ,"-N" ,username]
                p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                output, error = p.communicate()
                output = output.strip().decode("utf-8")
                error = error.decode("utf-8")
                if p.returncode != 0:
                    print(f"Error adding user: {error}")
                else:
                    print(F"{user} was added")

                cmd = ["sudo", "docker", "exec", "jupyterhub","bash", "-c" ,f"echo {username}:{username} | chpasswd"]
                p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                output, error = p.communicate()
                output = output.strip().decode("utf-8")
                error = error.decode("utf-8")
                if p.returncode != 0:
                    print(f"Error adding password: {error}")
                else:
                    print(F"{user} password was added")

                cmd = ["curl", "-XPOST", "--silent", "-k",f"https://$(hostname):9443/hub/api/users/{username}", "-H" ,f"Authorization: token {TOKEN}", "|", "jq"]
                p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                output, error = p.communicate()
                output = output.strip().decode("utf-8")
                error = error.decode("utf-8")
                if p.returncode != 0:
                    print(f"Error adding user to JH: {error}")
                else:
                    print(F"{user}  was added to JH")

                #To do: Convert api call to subprocess request
    return output
    

test_data = ["worker_1", "worker_2", "worker_3", "worker_4", "worker_5", "worker_6"]
txt_file = test_data  
print("Attempting add_user.sh script")
output = users_from_text(txt_file)
问题排查与解决

1. 脚本文件名不匹配

错误日志中明确提到找不到add_users_ERM_Linuxx.sh,但你实际使用的脚本是add_users_ERM.sh,文件名存在拼写差异(多了Linuxx后缀)。检查EMR步骤中指定的脚本文件名是否与实际上传的完全一致,包括大小写、拼写和后缀。

2. Python解释器路径有效性问题

脚本开头的shebang行#!/opt/conda/bin/python指定了Python解释器路径,需确认EMR主节点上该路径真实存在。可登录主节点执行ls /opt/conda/bin/python验证,若路径不存在,建议改为#!/usr/bin/env python3,该写法会自动查找系统环境中的Python3解释器,兼容性更强。

3. 脚本缺少可执行权限

确保脚本上传到EMR集群后拥有可执行权限。可在EMR步骤中添加前置命令chmod +x /mnt/var/lib/hadoop/steps/s-23QLFU7JXPPM7/add_users_ERM.sh,或在上传脚本时提前设置好权限(比如本地执行chmod +x add_users_ERM.sh再上传)。

4. Python脚本中混用Shell语法

你的脚本是Python文件,但直接使用了Shell语法,导致Python无法解析:

  • 获取TOKEN的Shell命令:TOKEN="$(sudo docker exec ...)"是Shell语法,Python无法识别,需改用subprocess执行命令并提取结果:
    import subprocess
    # 执行命令获取token
    token_result = subprocess.run(
        ["sudo", "docker", "exec", "jupyterhub", "/opt/conda/bin/jupyterhub", "token", "jovyan"],
        capture_output=True,
        text=True
    )
    # 提取最后一行作为token
    TOKEN = token_result.stdout.strip().split('\n')[-1]
    
  • 主机名获取:$(hostname)是Shell语法,Python中需导入socket模块获取主机名:
    import socket
    hostname = socket.gethostname()
    # 替换原URL中的$(hostname)
    api_url = f"https://{hostname}:9443/hub/api/users/{username}"
    
  • curl命令中的管道| jq:subprocess.Popen无法直接处理管道,需通过Shell执行整个命令,将shell=True参数传入:
    cmd = f"curl -XPOST --silent -k {api_url} -H 'Authorization: token {TOKEN}' | jq"
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    

内容的提问来源于stack exchange,提问作者Zizi96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 11:39:46