Bash: 查找 |标准 | xargs rm 不工作,但 rm 可以
Bash: find | sed | xargs rm not working, but rm does
我正在尝试从 src
的任何名为 __tests__
.
的子目录中删除所有 .js
和 .js.map
文件
$ find . -path './src/**' -name __tests__ | # find subdirectories
> sed -E 's/([^ ]+__tests__)/\/*.js \/*.js.map/g' | # for each subdirectory, concat *.js and *.js.map
> xargs rm # remove files
失败并出现以下错误:
rm: cannot remove './src/game/__tests__/*.js': No such file or directory
rm: cannot remove './src/game/__tests__/*.js.map': No such file or directory
rm: cannot remove './src/helpers/__tests__/*.js': No such file or directory
rm: cannot remove './src/helpers/__tests__/*.js.map': No such file or directory
但是,如果我将我的 xargs rm
更改为 xargs echo rm
,复制并粘贴输出,然后 运行 它就可以了。
$ find . -path './src/**' -name __tests__ | sed -E 's/([^ ]+__tests__)/\/*.js \/*.js.map/g' |
> xargs echo rm # echo command to remove files
rm ./src/game/__tests__/*.js ./src/game/__tests__/*.js.map ./src/helpers/__tests__/*.js ./src/helpers/__tests__/*.js.map
$ rm ./src/game/__tests__/*.js ./src/game/__tests__/*.js.map ./src/helpers/__tests__/*.js ./src/helpers/__tests__/*.js.map
在 $(...)
中包装我的 echo 的输出并在前面添加 rm
导致与以前相同的错误。
$ rm $(find . -path './src/**' -name __tests__ | sed -E 's/([^ ]+__tests__)/\/*.js \/*.js.map/g' | xargs echo rm
rm: cannot remove './src/game/__tests__/*.js': No such file or directory
rm: cannot remove './src/game/__tests__/*.js.map': No such file or directory
rm: cannot remove './src/helpers/__tests__/*.js': No such file or directory
rm: cannot remove './src/helpers/__tests__/*.js.map': No such file or directory
我做错了什么?
我怀疑这是否重要,但我在 Windows.
上使用 GitBash
您需要展开 glob (*
)。文件名扩展由 UNIX 上的 shell 执行,而不是由 rm
或其他程序执行。尝试:
.... | xargs -d $'\n' sh -c 'IFS=; for f; do rm -- $f; done' sh
...解释一下:
-d $'\n'
确保 xargs 仅在换行符(而不是空格!)上拆分,并阻止它把反斜杠和引号视为特殊字符。
sh -c '...' sh
运行s ...
作为脚本,sh
作为[=18=]
,后续参数在</code>等; <code>for f;
将因此迭代这些参数。
- 用
IFS=
清除 IFS
可防止 string-splitting 在 $f
未加引号使用时发生,因此只会发生 glob 扩展。
- 将
--
参数用于 rm
确保它将后续参数视为文件名,而不是选项,即使它们以破折号开头。
就是说,如果每个模式确实有很多文件,即使您使用的是 xargs,也可能 运行 到 "argument list too long"。
另一个警告是包含换行符的文件名可能会被拆分成多个名称(取决于您使用的 find
版本的详细信息)。一种适用于所有 POSIX-compliant 版本 find
的解决方法可能是:
find ./src -type d -name __tests__ -exec sh -c '
for d; do
rm -- "$d"/*.js{,.map}
done
' sh {} +
首先,解释一下这个问题:在find | sed | xargs rm
中,shell只是建立了那些程序之间的通信,但实际上并不以任何方式处理结果。这是一个问题,因为 *.js
需要通过 shell 扩展 以用文件名列表替换它; rm
将给定的每个参数都视为文字名称。 (这与 Windows 不同,其中程序自己进行 command-line 解析和 glob 扩展。
可以说,您根本不需要 find
。考虑:
shopt -s globstar # enable ** as a recursion operator
rm ./src/**/__tests__/*.js{,.map} # delete *.js and *.js.map in any __tests__ directory under src
...或者,如果您 想使用 find
,让它完成列出与 [=13 匹配的单个文件的工作=],而不是让这项工作稍后发生:
find src -regextype posix-egrep -regex '.*/__tests__/[^/]*[.]js([.]map)?' -delete
我正在尝试从 src
的任何名为 __tests__
.
.js
和 .js.map
文件
$ find . -path './src/**' -name __tests__ | # find subdirectories
> sed -E 's/([^ ]+__tests__)/\/*.js \/*.js.map/g' | # for each subdirectory, concat *.js and *.js.map
> xargs rm # remove files
失败并出现以下错误:
rm: cannot remove './src/game/__tests__/*.js': No such file or directory
rm: cannot remove './src/game/__tests__/*.js.map': No such file or directory
rm: cannot remove './src/helpers/__tests__/*.js': No such file or directory
rm: cannot remove './src/helpers/__tests__/*.js.map': No such file or directory
但是,如果我将我的 xargs rm
更改为 xargs echo rm
,复制并粘贴输出,然后 运行 它就可以了。
$ find . -path './src/**' -name __tests__ | sed -E 's/([^ ]+__tests__)/\/*.js \/*.js.map/g' |
> xargs echo rm # echo command to remove files
rm ./src/game/__tests__/*.js ./src/game/__tests__/*.js.map ./src/helpers/__tests__/*.js ./src/helpers/__tests__/*.js.map
$ rm ./src/game/__tests__/*.js ./src/game/__tests__/*.js.map ./src/helpers/__tests__/*.js ./src/helpers/__tests__/*.js.map
在 $(...)
中包装我的 echo 的输出并在前面添加 rm
导致与以前相同的错误。
$ rm $(find . -path './src/**' -name __tests__ | sed -E 's/([^ ]+__tests__)/\/*.js \/*.js.map/g' | xargs echo rm
rm: cannot remove './src/game/__tests__/*.js': No such file or directory
rm: cannot remove './src/game/__tests__/*.js.map': No such file or directory
rm: cannot remove './src/helpers/__tests__/*.js': No such file or directory
rm: cannot remove './src/helpers/__tests__/*.js.map': No such file or directory
我做错了什么?
我怀疑这是否重要,但我在 Windows.
上使用 GitBash您需要展开 glob (*
)。文件名扩展由 UNIX 上的 shell 执行,而不是由 rm
或其他程序执行。尝试:
.... | xargs -d $'\n' sh -c 'IFS=; for f; do rm -- $f; done' sh
...解释一下:
-d $'\n'
确保 xargs 仅在换行符(而不是空格!)上拆分,并阻止它把反斜杠和引号视为特殊字符。sh -c '...' sh
运行s...
作为脚本,sh
作为[=18=]
,后续参数在</code>等; <code>for f;
将因此迭代这些参数。- 用
IFS=
清除IFS
可防止 string-splitting 在$f
未加引号使用时发生,因此只会发生 glob 扩展。 - 将
--
参数用于rm
确保它将后续参数视为文件名,而不是选项,即使它们以破折号开头。
就是说,如果每个模式确实有很多文件,即使您使用的是 xargs,也可能 运行 到 "argument list too long"。
另一个警告是包含换行符的文件名可能会被拆分成多个名称(取决于您使用的 find
版本的详细信息)。一种适用于所有 POSIX-compliant 版本 find
的解决方法可能是:
find ./src -type d -name __tests__ -exec sh -c '
for d; do
rm -- "$d"/*.js{,.map}
done
' sh {} +
首先,解释一下这个问题:在find | sed | xargs rm
中,shell只是建立了那些程序之间的通信,但实际上并不以任何方式处理结果。这是一个问题,因为 *.js
需要通过 shell 扩展 以用文件名列表替换它; rm
将给定的每个参数都视为文字名称。 (这与 Windows 不同,其中程序自己进行 command-line 解析和 glob 扩展。
可以说,您根本不需要 find
。考虑:
shopt -s globstar # enable ** as a recursion operator
rm ./src/**/__tests__/*.js{,.map} # delete *.js and *.js.map in any __tests__ directory under src
...或者,如果您 想使用 find
,让它完成列出与 [=13 匹配的单个文件的工作=],而不是让这项工作稍后发生:
find src -regextype posix-egrep -regex '.*/__tests__/[^/]*[.]js([.]map)?' -delete