【问题标题】:flake8 behaves differently when run from within a bash script从 bash 脚本中运行时,flake8 的行为不同
【发布时间】:2018-11-05 21:59:13
【问题描述】:

我想这里的答案可能很简单,但我可能需要一些复杂的 bash 知识。我已经浏览 bash 文档几个小时了,但似乎找不到答案。

我正在开发一个 python 存储库,并想出了一个简单的脚本来仅对当前分支和主分支之间不同的文件进行 lint。这是从所述脚本 (lint.sh) 中提取的最小工作示例:

#!/bin/bash    
paths=$(git diff --name-only -r origin/master...HEAD | grep \.py$)    
flake8 $paths

出于测试目的,假设我只提交了一个文件bad.py,其内容如下:

hello
there

bash lint.sh 的预期输出为:

bad.py:1:1: F821 undefined name 'hello'
bad.py:2:1: F821 undefined name 'there'

但是,输出为空。在调试模式下运行时,bash 显示以下命令:

++ git diff --name-only -r origin/master...HEAD
++ grep '.py$'
+ paths='bad.py'
+ flake8 'bad.py'

这是我所期望的。另外,当我简单地运行flake8 bad.py 时,输出与预期的一样。

我希望这可能与不同 bash 版本之间的参数传递有关。 bash --version 的输出: GNU bash, version 4.4.23(1)-release (x86_64-apple-darwin17.5.0)

我会感谢所有的见解

【问题讨论】:

  • 你能从命令行和脚本中显示type -a flake8的结果吗?
  • 也可以在脚本中尝试flake8 'bad.py'
  • type 的输出在两种情况下都是相同的:flake8 is /Users/path/to/project/venv/bin/flake8 flake8 is /Users/filip/miniconda3/bin/flake8。从脚本运行 flake 'bad.py' 可以正常工作
  • 出于调试目的,您能否显示以下内容:set -x; python -c 'import sys; print(sys.argv[1:])' $paths(在脚本末尾)
  • err sorry, 更有用:set -x; python -c 'import sys; print(sys.argv[1:])' "$paths"

标签: bash git flake8


【解决方案1】:

很抱歉,这不是一个完全正确的答案,但肯定不适合评论!

这里给我的提示如下:

+ paths='bad.py'
+ flake8 'bad.py'

在我执行相同的脚本时,我得到以下信息:

$ bash -x lint.sh 
++ git diff --name-only -r origin/master...HEAD
++ grep '.py$'
+ paths=bar.py
+ flake8 bar.py
bar.py:1:1: F821 undefined name 'hello'
bar.py:2:1: F821 undefined name 'world'

请注意我的输出如何在文件名或分配周围包含引号。 bash 除非必要,否则通常不会添加引号。这告诉我可能该字符串中有某种控制字符(我最好的猜测是颜色或\b + 一些其他字符(这可能是截图的少数情况之一)真的很有帮助!))。

这是我能够重现您的发现的一种方式:

mkdir -p bin

cat > bin/grep << EOF
#!/usr/bin/env bash
exec /bin/grep --color=always "\$@"
EOF

chmod +x bin/grep

# simulate having this `grep` on your path
PATH=$PWD/bin:$PATH bash -x lint.sh

(虽然这似乎是一件很奇怪的事情,但过去我已经将自己的grep 放在~/bin 中,所以我可以添加--line-buffered --color=auto 现在GREP_OPTIONS is deprecated -- 可能会错误地添加--color=always 并让它工作......在大多数情况下)。今天我改为use an alias,因为即使这样我也遇到了锋利的边缘。

这种情况下的输出与您上面的输出相匹配:

$ PATH=$PWD/bin:$PATH bash -x lint.sh
++ git diff --name-only -r origin/master...HEAD
++ grep '.py$'
+ paths='bar.py'
+ flake8 'bar.py'

但棘手的提示在于突出显示

附录

虽然与您的问题无关,但这里可能是完成您想要的更好的方法:

# if you have GNU xargs
git diff -z --name-only origin/master...HEAD -- '*.py' | xargs --null --no-run-if-empty flake8

# if you need to be more portable (I see you're probably on macos)
git diff -z --name-only origin/master...HEAD -- '*.py' | xargs -0 flake8 /dev/null

不同部分的解释:

  • git diff -z:以空字节分隔的输出文件名。如果文件名包含空格或其他特殊字符,这可以防止拼接
  • xargs --null:在喷射参数时将输入拆分为空字节
  • xargs --no-run-if-empty:如果没有参数,则根本不运行可执行文件(这是 GNU 扩展)
  • xargs -0:与xargs --null 相同,但是如果您坚持使用非 GNU xargs,您将无法访问长选项
  • flake8 /dev/null:这是一个偷偷摸摸的把戏,因为 bsd xargs 没有“如果为空则不运行”选项,它总是会调用 flake8。如果flake8 被零参数调用,它默认递归您当前的工作目录(并检查所有文件)。通过将 /dev/null 放在开头,可以防止这种行为,而是 lints 一个空文件!

附录 2,您可能需要考虑使用 git hooks 框架来为您处理所有这些,我维护 pre-commit 旨在消除 git 周围的许多粗糙边缘(例如这个!)。

【讨论】:

  • 哦,这太棒了。原来我的.bash_profile 中有GREP_OPTIONS='--color=always',这导致了特殊字符的存在
猜你喜欢
  • 1970-01-01
  • 2016-10-20
  • 2017-02-28
  • 2012-06-22
  • 2012-04-10
  • 2016-04-09
  • 2023-04-07
  • 1970-01-01
  • 2017-11-04
相关资源
最近更新 更多