一些背景故事,因为也许我的方法从根本上是错误的:
当前,我正在尝试制作一个预提交脚本,该脚本检查哪些文件已更改并将其传递给linter。这是我目前拥有的:
STAGED=$(git diff --cached --name-only --diff-filter=ACM | grep -E "\.js$")
echo "${STAGED}" | xargs -I {} eslint {}
这确实有效,但是有一个缺陷:它会为每个文件启动一个新进程,并且可以想象,当给定多个文件时,延迟会非常大(是的,手动在整个文件夹上启动此进程不会只需在单个文件上启动20次以上即可。
我尝试将-n $(echo ${STAGED} | wc -l)
传递给xargs,但这并没有改变。
我也尝试这样做:
eslint $(echo ${STAGED} | sed -E "s/^(.*)$/\"\1\"/g" | tr "\n" " ")
那里有报价以确保正确处理带有空格的文件。但这根本不起作用。
我尝试的另一件事是更改IFS
:
OLD_IFS="${IFS}"
IFS=$'\n'
eslint "${STAGED}"
IFS="${OLD_IFS}"
那对我也不起作用。
这个问题有解决的办法吗?
答案 0 :(得分:1)
如果您使用的是GNU grep平台,请考虑:
git diff --cached --name-only --diff-filter=ACM -z |
grep -zZ '[.]js$' |
xargs -0 eslint
...在非GNU平台上,可以改为:
git diff --cached --name-only --diff-filter=ACM -z |
while IFS= read -r -d '' name; do [[ $name = *.js ]] && printf '%s\0' "$name"; done |
xargs -0 eslint
此处最重要的更改是未使用xargs -I
,这意味着-n 1
。
使用git diff -z
,grep -zZ
和xargs -0
用NUL字节分隔文件名,这意味着即使使用换行符的名称也将得到正确处理。 (git
可能不允许使用它们,但是在整个UNIX系统上通常都允许使用它们,因此养成安全处理它们的习惯是很卫生的。)
另一种方法是将命令结果读入数组。假设bash的版本足够新(4.4),并且文件列表的大小不超过单个命令行的大小(需要xargs
):
readarray -d '' changed_files < <(git diff --cached --name-only --diff-filter=ACM -z)
eslint "${changed_files[@]}"