heredocs 如何与 xargs 一起使用?
How can heredocs be used with xargs?
背景
我希望在发送之前从 git archive
输出的某些 python 源代码文件中删除任何 # TODO
注释。我希望通过一个来自各种 *nix 操作系统的 运行 脚本来做到这一点,因此它应该尽可能 POSIX 兼容。
我知道 find -print0
和 xargs -0
不在基本规范中,但它们似乎很常见,我可以使用它们(除非存在更好的替代方案).我正在使用 ed
,因为 sed -i
不在就地编辑的基本规范中。假设下面的命令是 运行 来自一个已经没有 tar 的 git 存档的目录。
我很高兴有一个整体的替代解决方案来删除 # TODO
注释,但为了满足我的好奇心,我还想知道我在使用命令时遇到的特定问题的答案想出了。
现有代码
find . -type f -name "*.py" -print0 | xargs -0 -I {} ed -s {} << 'EOF'
,g/^[ \t]*#[ \t]*TODO/d
,s/[ \t]*#[ \t]*TODO//
w
EOF
预期结果
所有以“.py”结尾的文件都去除了仅包含 TODO 注释的完整行,或行尾注释 tar 包含 TODO。
实际结果
(标准输出)
,g/^[ \t]*#[ \t]*TODO/d
,s/[ \t]*#[ \t]*TODO//
w
: No such file or directory
当前理论
我相信 << 'EOF'
heredoc 被应用于 xargs
而不是 ed
,我不确定如何解决这个问题。
修复 << 'EOF'
heredoc 方向会采取一些 sh -c
技巧,最终会导致更多问题,因此我尝试重新解决问题而根本不需要 heredoc。
我最终登陆:
inline() {
# Ensure a file was provided
in="${1?No input file specified}"
# Create a temp file location
tmp="$(mktemp /tmp/tmp.XXXXXXXXXX)"
# Preserve the original file's permissions
cp -p "$in" "$tmp"
# Make $@ be the original command
shift
# Send original file contents to stdin, output to temp file
"$@" < "$in" > "$tmp"
# Move modified temp file to original location, with permissions and all
mv -f "$tmp" "$in"
}
find . -type f -name "*.py" -exec grep -ilE '#[ \t]*TODO' {} \+ | while read file; do
inline "$file" sed -e '/^[ \t]*#[ \t]*TODO/ d' -e 's/[ \t]*#[ \t]*TODO//'
done
mktemp
在技术上不在基本规范中,但 appears to be fairly portable 所以我很好地包括它。 ed
也给我带来了一些问题,所以我回到 sed
使用自定义函数来复制不可用的 -i
标志以进行就地操作。
背景
我希望在发送之前从 git archive
输出的某些 python 源代码文件中删除任何 # TODO
注释。我希望通过一个来自各种 *nix 操作系统的 运行 脚本来做到这一点,因此它应该尽可能 POSIX 兼容。
我知道 find -print0
和 xargs -0
不在基本规范中,但它们似乎很常见,我可以使用它们(除非存在更好的替代方案).我正在使用 ed
,因为 sed -i
不在就地编辑的基本规范中。假设下面的命令是 运行 来自一个已经没有 tar 的 git 存档的目录。
我很高兴有一个整体的替代解决方案来删除 # TODO
注释,但为了满足我的好奇心,我还想知道我在使用命令时遇到的特定问题的答案想出了。
现有代码
find . -type f -name "*.py" -print0 | xargs -0 -I {} ed -s {} << 'EOF'
,g/^[ \t]*#[ \t]*TODO/d
,s/[ \t]*#[ \t]*TODO//
w
EOF
预期结果
所有以“.py”结尾的文件都去除了仅包含 TODO 注释的完整行,或行尾注释 tar 包含 TODO。
实际结果
(标准输出)
,g/^[ \t]*#[ \t]*TODO/d
,s/[ \t]*#[ \t]*TODO//
w
: No such file or directory
当前理论
我相信 << 'EOF'
heredoc 被应用于 xargs
而不是 ed
,我不确定如何解决这个问题。
修复 << 'EOF'
heredoc 方向会采取一些 sh -c
技巧,最终会导致更多问题,因此我尝试重新解决问题而根本不需要 heredoc。
我最终登陆:
inline() {
# Ensure a file was provided
in="${1?No input file specified}"
# Create a temp file location
tmp="$(mktemp /tmp/tmp.XXXXXXXXXX)"
# Preserve the original file's permissions
cp -p "$in" "$tmp"
# Make $@ be the original command
shift
# Send original file contents to stdin, output to temp file
"$@" < "$in" > "$tmp"
# Move modified temp file to original location, with permissions and all
mv -f "$tmp" "$in"
}
find . -type f -name "*.py" -exec grep -ilE '#[ \t]*TODO' {} \+ | while read file; do
inline "$file" sed -e '/^[ \t]*#[ \t]*TODO/ d' -e 's/[ \t]*#[ \t]*TODO//'
done
mktemp
在技术上不在基本规范中,但 appears to be fairly portable 所以我很好地包括它。 ed
也给我带来了一些问题,所以我回到 sed
使用自定义函数来复制不可用的 -i
标志以进行就地操作。