我有一堆我正在调试的脚本,所有脚本都是嵌套的,非常讨厌。
只是想知道我是否能够设置一些相当于bash的-x选项的环境变量。这将节省我惊人的时间。
我已经找到了答案,但似乎它不存在 - 希望你聪明的人可以提供建议,或者可能是另一种解决方案。
谢谢!
答案 0 :(得分:8)
因为你似乎陷入了困境,我会建议一些可怕的选择(一种选择听起来很可怕,但并不是那么糟糕)。
首选:使用不同的工具。 strace(1)
和ltrace(1)
都可以提供一系列令人惊叹的信息 - 尽管双方都不了解shell变量,但将向您展示脚本如何与其余部分进行交互系统和程序的一些内部状态。这可能已经足够了。 (如果您是strace(1)
的新用户,请尝试strace -f -o /tmp/foo ./program
- 它会跟随fork(2)
,vfork(2)
和clone(2)
来电,因此会遵循子流程并转储。输出转到/tmp/foo
。)
第二选择:在所有脚本中用#!/bin/bash
替换所有#!/bin/bash -x
:
find . -type f -print0 | xargs -0 sed -i -e 's/^#!\/bin\/bash$/#!\/bin\/bash -x/'
也许有更好的机制来替换所有脚本上的shebang线,但这感觉还不错。在通过脚本调用的C程序中,它会错过system(3)
,popen(3)
等的所有用法,但这可能会很好。如果任何脚本依赖于/bin/bash
的参数,您可能需要更加努力地正确添加-x
。
最后一个选择:以root身份启动sash(1)
shell。将/bin/bash
复制到/bin/real.bash
。编写一个快速而肮脏的C程序,将-x
添加到/bin/real.bash
的命令行参数,并将放入/bin/bash
。这将获得所有:每system(3)
,每popen(3)
,每个初始化脚本,所有cron作业,所有用户登录,所有内容。
你可以稍微修改一下最后一个选择; Linux内核提供了每个进程的私有名称空间,可用于使新的/bin/bash
对给定进程的 children 可见。这有点复杂......
bash
:cp /bin/bash /bin/real.bash
-x
添加到命令行参数并调用/bin/real.bash
。 (让我们称之为/bin/wrapper.bash
。)/
装载shared
:mount --make-shared /
unshare --mount bash
bash
中,将/
设为奴隶:mount --make-slave /
bash
中,绑定您的替换bash
:mount -B /bin/wrapper.bash /bin/bash
bash
中,启动您的shell脚本。它们都将被重定向到您的包装器。不属于 new bash
的流程将继续使用“真实”/bin/bash
,该版本未经修改。当最后一个(grand)*子进程终止时,私有命名空间和有趣的绑定挂载也会消失。
所有这些有趣的业务的结果是所有的shell脚本都保持不变,你可以使用你认为最有用的调试工具。如果你恰到好处地眯着眼睛,那就不是很干扰了。
我在我的工作站上执行了很多这些步骤(除了我使用--make-rshared
和--make-rslave
,而是使用/bin/dir
和/bin/ls
代替/bin/bash
进行了测试),并在新命名空间内和新命名空间外的shell中使用ls -li /bin/dir /bin/ls
检查inode编号,并且命名空间外的进程继续看到inode编号保持不变,但命名空间内的进程看到dir
和ls
分享inode号码。
有关命名空间,私有挂载和绑定挂载的完整详细信息,建议您阅读内核源代码树中的Documentation/filesystems/sharedsubtree.txt
文件,clone(2)
手册页,unshare(1)
手册页,以及mount(8)
手册页。
绑定坐骑会在系统重启时消失,所以你不能把任何东西搞得太糟糕。 :)
答案 1 :(得分:2)
不,它不受环境变量的控制,但您可以在需要的地方set -x
执行,set +x
将其关闭。