我有几个带有文件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或任何其他命令以使其在制作过程中起作用(makefile是3rdparty软件,我不想在每次需要升级时对其进行修补) ?
答案 0 :(得分:1)
简短版本:您不能(而且您可能不想要)。
长版本:您已经定义了一个shell函数。实际上,您甚至可以将该Shell函数导出到环境export -f cat
中。但是除非Makefile在说bash -c cat ...
而不是说cat
(或其他引用相同的效果),否则它不会给您想要的行为。
如果您真的坚持……而Makefile没有使用硬编码路径(例如/bin/cat
)。您可以编写自己的猫,将其放置在某个地方,并在cat
的其他可能命中位置之前放置该猫(只需将它放在前面)。
也有机会(在make文件中查看)它使用变量(例如CAT
)来知道要调用的内容,因此,您可以仅提供自己的定义。
尽管如此。我不鼓励您使用此类变通办法,因为这样做会混淆机器的实际行为。这里声明了一些东西……环境中的其他东西赋予了它不同的含义。这是错误的非常常见的来源,并最终导致非显而易见的(难以解决的)错误。
功能位示例/说明。我有一个Makefile:
all:
@echo foo
并定义并导出函数“覆盖”回显。 echo() { /bin/echo "$@" bar; } ; export -f echo
。我运行make and get:
$ make
foo
因为make只在echo
中寻找PATH
(尝试exec
之后找到它,然后运行它)。如果我将其更改为介于bash之间,则导出的函数将启动,但是...这是在make中使用命令的常用方式,因此您必须编辑不需要的Makefile:
all:
@bash -c 'echo foo'
这将为您提供所需的结果:
$ make
foo bar
我提到的另一个选项。我已将该功能的行为放入脚本/tmp/bin/echo
中,内容为:
#!/bin/bash
/bin/echo "$@" bar
并且我已经修改了PATH
环境变量export PATH=/tmp/bin:$PATH
。现在,即使使用Makefile的第一种形式:
all:
@echo foo
我得到:
$ make
foo bar
但是,如果给出的Makefile改为说/bin/echo
,那么我就没有这种运气了。您仍然可以更改二进制文件...,也可以通过强制共享库预加载来更改其行为...但是听起来引人注目,并且充分揭示了为什么这实际上不是采用二进制文件的最佳方向。
答案 1 :(得分:1)
您不能使用shell函数来执行此操作,因为shell函数仅存在于本地shell中。它不会传递给make
之类的程序。另外,GNU make总是默认调用/bin/sh
而不是/bin/bash
,并且您上面的shell函数是用bash语法编写的,因此将其放入~/.bashrc
中不会有影响。
您可以运行:
$ make SHELL=/bin/bash
并将该shell函数添加到您的~/.bashrc
中,这可能会起作用。
您唯一可以做的另一件事(假设您的第三方makefile直接调用cat
而不使用$(CAT)
之类的变量)是创建一个cat
shell脚本(不是函数),并在调用make时将其放在PATH
和/bin
之前的/usr/bin
上。像这样:
$ mkdir tmp
$ vi tmp/cat
...add commands...
$ chmod 755 tmp/cat
$ PATH=$(pwd)/tmp:$PATH make ...
当然,执行此操作时,不能在脚本中使用command cat ...
,而必须使用完全限定的路径,例如/bin/cat ...