Bash中检查所需命令与接口的讨论
你好,我是无能。
我结束了在公司的最后一天工作,从同一个公司的女孩那里收到了巧克力,在离职前不久被请去吃了烤肉,还和一位做了25年网络工作的人聊了他的过去和现在的家庭网络环境,以及我自己的家庭服务器相关的话题,度过了愉快的时光。
我尽力做到了我这个不成熟的人能做到的事情,但由于我有很多不足之处,所以感到很抱歉。
我每天都觉得Shell脚本非常强大。
当然,其可移植性差,确实无法像目前FreeBSD默认Shell中存在的csh那样进行函数式描述,这个问题是不可否认的。
然而,我实际上认为Shell脚本的优势在于其接口处理的便捷性。
C语言与Shell脚本的接口
例如,假设在Shell脚本中像下面这样使用echo。
echo "test"
这相当于C语言中的标准输出。
#include <stdio.h>
int main() {
const char *message = "test";
// 标准输出にメッセージを出力
fprintf(stdout, "%s\n", message);
return 0;
}
如果输出到标准错误输出,则进行如下重定向。
echo "testerr" 1>&2
而在C语言中,则对应如下。
#include <stdio.h>
int main() {
const char *message = "testerr";
// 標準エラー出力にメッセージを出力
fprintf(stderr, "%s\n", message);
return 0;
}
此外,大多数GNU/Linux命令执行失败时的返回值,由于过去的开发者们的精心设计,使得判断条件的测试变得容易,如果将其作为脚本语言来使用,则非常有效。
然而,问题在于,这只有在可以使用Shell脚本的环境下才能受益。
即使使用其他语言编写类似的代码,其通用性也有效,但命令在某种程度上是以语言中的库的形式运行的,我认为这也是其通用性被认为不足的原因。
然而,我个人认为能够如此简洁地操作文件描述符是非常强大的。
else也只需连接两个管道即可。
※写完后才想到,严格来说这并不是else呢^^;
它只是在返回值非0时执行类似else的操作而已。
$ curl aa || echo "wtf"
curl: (6) Could not resolve host: aa
wtf
如果我在初中时就知道这么方便的东西,那该多好啊。
我希望任何网站都能提供更多学习Shell脚本的场所。
话说回来,现在回想起来,当时的GNU/Linux日语环境相当困难,日语输入的预测转换也达不到实用的水平,所以我记得。也许正是因为Chrome OS的普及,OSS日语输入才得以繁荣,才有了现在这种便利。
我记得在初中时期,我为一位古怪的朋友设置了一台安装了Ubuntu的ThinkPad,因为他想要一台...
那么,命令检查该怎么做?
我一直在想,在Bash Shell脚本中编写命令检查时,有没有一种更智能、更易读的写法。
话虽如此,将数组传递给循环处理的for循环当然很方便,但看看数组存储时的写法。
#!/bin/bash
cmds=(aa bb cc)
for i in ${cmds[@]}; do
command -v $i 1> /dev/null || echo "Please install $i"
done
使用()将命令存储为数组到cmds中,并使用${cmds[@]}展开数组。
但是,如果命令增加,每次都添加到cmds=()中,就会觉得是否有必要写在这里呢?
在其他语言中,依赖关系信息通常存储在Cargo.toml、deno.json、go.mod、Gemfile,以及不太受欢迎的requirements.txt等文件中。
如果有一个像那样汇总的文件,那会很方便。
因此,我尝试了这样的方法。
#!/bin/bash
cat ./cmd | xargs which 1> /dev/null || echo "Please install cmd"
那么,cmd文件是什么样的呢?
$ cat cmd
ls
pwd
cargo
实际上,我本想用command命令来检查,但command作为Shell的内部命令运行,无法传递给xargs。
$ which command
which: no command in (/home/haturatu/.rbenv/bin:/home/haturatu/.rbenv/shims:/home/haturatu/.deno/bin:/home/haturatu/.cargo/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/opt/android-sdk/platform-tools:/var/lib/flatpak/exports/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/usr/lib/plan9/bin:/home/haturatu/.local/bin:/home/haturatu/.local/bin:/home/haturatu/Android/Sdk/cmdline-tools/tools/bin:/home/haturatu/Android/Sdk/platform-tools:/home/haturatu/Android/Sdk/emulator:/home/haturatu/Android/Sdk/tools:/home/haturatu/Android/Sdk/tools/bin:/home/haturatu/Android/Sdk/cmdline-tools/tools/bin:/home/haturatu/Android/Sdk/platform-tools:/home/haturatu/Android/Sdk/emulator:/home/haturatu/Android/Sdk/tools:/home/haturatu/Android/Sdk/tools/bin:/home/haturatu/.npm-global/bin:/home/haturatu/go/bin)
如果我错了,很抱歉,但我认为当通过xargs传递时,它会作为xargs的独立进程运行,而不是执行bash的进程,因此可能无法识别。
因此,虽然无法将which失败的命令传递给Please install cmd,但在此之前which会输出错误信息,所以我觉得可能不需要。
※写完后才想到,如果用xargs /bin/bash command -v也许可以...
将这组命令放在单独的文件中还有一个好处。
可以从这个文件批量安装。
cat cmd | xargs -I {} sudo pacman -S --noconfirm {}
对于apt,也可以使用-y选项实现同样的效果。
所以,姑且不论我是否真的会使用,我先把它作为一个想法留在这里。
那么,下次再见。请多关照。(从年终总结文章开始,不知不觉写了好几篇文章,这大概是我的错觉吧)