我有几个文件stamp1.txt和stamp0.txt的目录,我想要覆盖cat命令。例如,我需要它来禁止"stamp1"文件存档到库中。
所以我写了一个名为"realname"的小过滤器程序和 bash 脚本来覆盖原始的 cat 命令。
function cat() {
local e=""
for s in $@
do
if realname $s; then
e=$e" "$s;
fi
done
command cat $e;
}
所以命令:
cat dir1/stamp1.txt dir2/stamp0.txt
将转换为
cat dir2/stamp0.txt
这个例子工作得很好
ar cruv some_lib.a `cat dir1/stamp1.txt dir2/stamp0.txt`
但是当我运行一些makefile来构建一些软件时 - 在这个过程中使用了原始的cat也没有被覆盖。
如何在不更改makefile的情况下覆盖cat或任何其他命令以使其在make过程中工作(makefile是第3方软件,我不想每次需要升级时都修补它(?
你不能用 shell 函数做到这一点,因为 shell 函数只存在于本地 shell 中。 它不会传递给像make
这样的程序。 此外,GNU make 默认总是调用/bin/sh
,而不是/bin/bash
,并且上面的 shell 函数是用 bash 语法编写的,因此将其放在您的~/.bashrc
中不会有任何影响。
您可以运行:
$ make SHELL=/bin/bash
并将该 shell 函数添加到您的~/.bashrc
中,这可能会起作用。
您唯一可以做的其他事情(假设您的第三方 makefile 直接调用cat
并且不使用像$(CAT)
这样的变量(是创建一个cat
shell 脚本(不是函数(并将其放在PATH
上,然后再/bin
,并在调用 make 时/usr/bin
。 像这样:
$ mkdir tmp
$ vi tmp/cat
...add commands...
$ chmod 755 tmp/cat
$ PATH=$(pwd)/tmp:$PATH make ...
当然,当您执行此操作时,您不能在脚本中使用command cat ...
,您必须使用完全限定的路径,例如/bin/cat ...
简短版本:你不能(你可能不应该想要(。
更长版本:你已定义一个 shell 函数。您实际上甚至可以将该 shell 函数导出到环境中export -f cat
。但是,除非 Makefile 说bash -c cat ...
而不仅仅是cat
(或其他对相同效果的引用(,否则它不会给你你想要的行为。
如果你真的坚持...并且生成文件没有使用硬编码路径(例如/bin/cat
(。你可以写你自己的猫,把它放在某个地方,让这个位置先于其他可能的点击cat
(把它放在前面(。
也有一些机会(查看 make 文件(它使用了一个变量(例如CAT
( 知道该怎么称呼,因此如果是这种情况,您可以提供自己的定义。
无论如何。我不鼓励您使用这样的解决方法,因为这样做会使机器的实际行为变得模糊。这里声明了一些东西...以及环境中的其他东西赋予它不同的含义。这是错误和最终不明显(更难解决(错误的非常常见的来源。
功能位的示例/说明。我有一个制作文件:
all:
@echo foo
并定义并导出"覆盖"echo 的函数。echo() { /bin/echo "$@" bar; } ; export -f echo
.我运行制作并得到:
$ make
foo
因为 make 只是在PATH
中寻找echo
(尝试exec
,一旦找到它,它就会运行它(。如果我将其更改为在两者之间有 bash 步骤,导出的功能将启动,但是......这是在make中使用命令的常用方法,您必须编辑您不想要的Makefile:
all:
@bash -c 'echo foo'
这将产生您想要的结果:
$ make
foo bar
我提到的另一个选项。我已经将该函数的行为放入脚本中,/tmp/bin/echo
阅读:
#!/bin/bash
/bin/echo "$@" bar
我已经修改了PATH
env varexport PATH=/tmp/bin:$PATH
.现在,即使使用Makefile的第一种形式:
all:
@echo foo
我得到:
$ make
foo bar
但是,如果给出的 Makefile 说/bin/echo
,我就没有这样的运气了。您仍然可以更改二进制文件...或者通过强制共享库预加载来更改其行为...但听起来很极端,并充分揭示了为什么这真的可能不是最好的方向。