Python sys.argv[1:]未识别命令行选项

4 投票
2 回答
2719 浏览
提问于 2025-04-16 11:11

更新/解决方案:答案在下面,来自 Zack。问题确实出在脚本文件 clenotes.cmd 上的 DOS 换行符。因为我对各种文件进行了很多操作,所以我删除了整个目录,然后从 这里 重新下载了一个新的副本。我像这样在文件上运行了 Zack 的 perl 脚本:

perl -pi.bak -e 's/[ \t\r]+$//' clenotes.cmd

然后我稍微修改了一下命令执行,最终的脚本变成了:

CWD=`dirname $0`
JYTHON_HOME="$CWD"
LIB_DIR="$JYTHON_HOME/lib"
NOTES_HOME="/opt/ibm/lotus/notes/"
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$NOTES_HOME
java -cp "$LIB_DIR" -jar "$LIB_DIR/jython.jar" -Djython.home="$CWD/" -Dpython.path="$LIB_DIR:$CWD/ext" -Djava.library.path="$NOTES_HOME" "$LIB_DIR/clenotes/cletes/clenotes.py" "$@"

就这样——其他一切都正常工作。clenotes.py 或 clenotes.cfg 不需要任何修改。非常感谢大家耐心等待这个问题,我想这其实是个很简单的事情。


更新:我在减少一些代码,以使其更易读,并去掉帖子中不必要的信息。


我正在尝试让 Lotus Notes 命令行 在 Linux 上运行,但在 python 文件中遇到了与 sys.argv[1:] 相关的问题。Windows 脚本在这里:

@echo off
@setlocal 
set CWD=%~dp0
set JYTHON_HOME=%CWD%
set LIB_DIR=%JYTHON_HOME%/lib
java -cp %LIB_DIR% -jar %LIB_DIR%/jython.jar -Djython.home=%CWD%  -python.path=%LIB_DIR%;%CWD%/ext %LIB_DIR%/clenotes/clenotes.py  %*

@endlocal

我在处理变量时遇到了困难,所以在 Linux 上,它看起来就是这样:

java -cp ./lib/ -jar ./lib/jython.jar -Djython.home=./ -Dpython.path=./lib:./ext -Djava.library.path=/opt/ibm/lotus/notes/ ./lib/clenotes/clenotes.py $*

我是在目录内运行它的。无论如何,让我困惑的是,它没有识别我从命令行传递的任何选项。clenotes.cmd --help 的结果是

No commands specified. Use --help option for usage.

这是命令行参数应该被解析的部分:

def main():    

  Output.log("Entering %s v%s" % (PROGRAM_NAME,VERSION),Output.LOGTYPE_DEBUG)
  cliOptions2=[]
  for opt in cliOptions:
    opt2=opt.replace('--','')
    opt2=opt2.replace('!','=')
    cliOptions2.append(opt2)
  opts=[]
  args=[]
  try:
    opts, args = getopt.getopt(sys.argv[1:], '', cliOptions2)

我在 Arch Linux 64 位的 32 位 chroot 环境中使用 Python 3.1.3。我还需要提供其他信息吗?

以防需要... 这里 是整个 clenotes.py 文件。

此外,按照评论中的要求,配置文件(包含帮助信息和可用选项/参数)在 这里


更新

经过很多尝试,我取得的最佳进展是检查它在(主)方法中设置的 opts 和 args。最令人惊讶的是,当传递一个参数并查看其解析结果时,使用 print sys.argv,选项后面会带有一个 \r。例如:

clenotes.cmd appointments
args is ['appointments\r']

在 Windows 上我做了同样的事情,args 被报告为 ['appointments']。此外,手动设置 args=['appointments'] 然后注释掉 getopt.getopt 分配值的部分也能正常工作。

最后,我发现当使用多个参数时,n-1 个参数会被解析并使用,而第 n 个参数会被忽略。这算是一种变通方法,因为我实际上可以使用这个脚本……但显然这不是首选。如果我想查看今天的预约,我可以执行 clenotes.cmd appointments --today --today,它会正常工作。sys.argv 会输出:['appointments', '--today', '--today\r']

那么……是什么导致了尾部的 \r?我觉得这可能与实际脚本有关。再注意一下:

java -cp ./lib/ -jar ./lib/jython.jar -Djython.home=./ -Dpython.path=./lib:./ext -Djava.library.path=/opt/ibm/lotus/notes/ ./lib/clenotes/clenotes.py $*

所以……一堆路径的东西,然后是实际的 python 文件:clenotes.py $*

我从 这里 得到了 $*

它是不是在捡起回车符??

2 个回答

3

我还得继续找找看那个 \r 是从哪里来的。不过在此之前,这个问题变得简单多了。一旦参数解析完,就这样做:

args = [arg.strip() for arg in args]

这样就能去掉 \r 了。

编辑:等等——这只是部分解决方案吗?选项还是解析不正确吗?

编辑2:看起来 \r 需要更早去掉。当没有命令的时候,\r 根本没被去掉,因为上面的代码只是在 getopt 完成后才去掉 \r。这本该是我之前就能想到的——而不是在这里传递 sys.argv[1:]

opts, args = getopt.getopt(sys.argv[1:], '', cliOptions2)

先修改它

argv = [arg.strip() for arg in sys.argv[1:]]
opts, args = getopt.getopt(argv, '', cliOptions2)

你也可以直接用 sys.argv[-1] = sys.argv[-1].strip()... 不过作为一个C语言程序员,我看到这个有点不舒服。我知道这可能有点无理。

或者就按照Zack说的,把clenotes.cmd转换成Linux格式——不过要注意,这样去掉会确保其他人不需要再解决同样的问题。(另一方面,这样做有点丑,或者至少对不期待这种问题的人来说有点神秘。)

5

我觉得你的问题是因为 clenotes.cfg 文件使用了 DOS 格式的换行符,而 Python 误解了这个格式。试着把 clenotes.py 里的这一行改成:

config.readfp(open('%sconfig/clenotes.cfg' % System.getProperty('jython.home')))

这样读取

config.readfp(open('%sconfig/clenotes.cfg' % System.getProperty('jython.home'), "rU"))

这里的 "rU" 是告诉 Python,虽然它是在 Unix 系统上运行,但它需要准备好处理包含 DOS 格式换行符的文件。你可以查看这个链接 http://docs.python.org/library/functions.html#open,向下滚动到以 "除了标准的 fopen() 模式..." 开头的段落。

(或者你可以运行这个命令: perl -pi.bak -e 's/[ \t\r]+$// clenotes.cfg -- 这会把文件转换成 Unix 格式的换行符。如果我是你,我可能会同时做这两件事。)

(如果以上建议都没有帮助,我会尝试用上面的 perl 命令直接处理 clenotes.py 文件。我不认为这会是问题,但如果 \r 字符不是来自 clenotes.cfg,那么 .py 文件就是唯一可能的来源。)

(编辑:根据你在问题中的评论,我现在认为需要把 clenotes.cmd 这个外壳脚本也从 DOS 格式转换成 Unix 格式的换行符。)

撰写回答