来自这个问题:ls 总是会列出 rm 将删除的文件吗?@fkraiem 评论道:
我有点惊讶 rm 没有 --dry-run 标志......
这让我想起了以前使用命令seq
生成 1-100 的数字序列的情况。问题是列表有一个前缀Item
seq 100
生成:
1
2
3
...
100
而我想要的是:
Item 1
Item 2
Item 3
...
Item 100
以 seq 命令为例,我是否可以添加一个--prefix=[PREFIX]
标志,自动将前缀添加到生成的序列列表中?
我不是在谈论 bash 别名
答案1
一般来说,除了修改命令的代码(并在编译的可执行文件的情况下重新编译)之外,您还需要编写一个包装函数 - 作为 shell 函数或位于原始可执行文件前面的可执行脚本PATH
。 它需要:
- 解析命令行参数
- 拦截你的附加选项(以及任何特定于选项的参数)
- 执行新操作
- 否则将剩余参数传递给原始命令
但是你seq
应该已经有一个选项来指定数字格式,它可以被(滥用)用来获取你想要的列表类型
-f, --format=FORMAT use printf style floating-point FORMAT
前任。
$ seq -f 'Item %.0f' 1 10
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
更一般地,您可以使用printf
例如printf 'Item %d\n' $(seq 1 100)
或(使用 bash 的内置括号扩展)printf 'Item %d\n' {1..100}
顺便说一下,确实rm
有一种试运行标志,-i
-i prompt before every removal
或(不太便携)
-I prompt once before removing more than three files, or when removing recursively; less intrusive than -i, while still giving protection against most mistakes
答案2
添加标志和现有命令
已编译的二进制文件形式的命令无法修改,因此无法添加标志。当然,可以尝试修改可执行文件本身的二进制数据,但这非常困难且不切实际。更实际的做法是获取源代码,修改源代码,然后重新编译命令。如果命令是脚本(Perl、Python、shell 等),则可以使用 root 权限直接修改它。但是,所有这些方法都有共同的问题:
- 修改命令可能违反许可条款。本网站答案的读者经常认为 Ubuntu 下所有东西都是开源和自由的,但也使用专有软件。当然,你能修改任何软件 - 这不是能力或编码能力的问题。通常问题是你是否可能修改它。
- 可移植性,即此标志在您修改它的这台机器上有效,但在另一台机器上无效。间接地,文档。想象一下,您编写了一个使用修改版本的脚本
seq
,但您添加的任何标志都不在手册页中。您的同事或其他阅读此脚本的人会非常困惑为什么该标志不在手册中,甚至可能更加困惑为什么该标志不起作用;更有趣的是,当您拥有一整套可能依赖于带有该特定标志的特定命令的实用程序时。这可能会让您的同事非常不高兴。并且,如果您重新分发(即给他们)修改后的命令的副本,那么您现在就会遇到许可问题(伊纳尔,但这可能会引发诉讼)。 - 回到同事的话题,修改应该是标准的命令可能会破坏他们的工作流程并扰乱开发环境。
更好的解决方案
当您想要自定义标志时,一般的想法是使用原始命令的包装器。这可以是您的 中的函数~/.bashrc
、已编译的程序、脚本 - 等等。关键点是它应该只在您的环境中使用,并且您应该知道何时为自己编写命令以及何时为他人编写命令。
以下是一些选项/建议:
- 在您的 中定义功能
~/.bashrc
。函数优先于命令位于PATH
变量中的任何目录中。 - 命名应明确无误。例如,将自己的命名
seq
与此相同会产生歧义,因为两者的功能会有所不同。更好的方法是使用my_seq
或seq_f
来表示功能。脚本通常具有.sh
扩展名,因此这应该有助于消除歧义。 - 如果您正在修改已编译的二进制文件,请让它存在于您的文件中
~/bin
,并可能重命名它。 - 考虑使用
~/bin/mycommand
而不是仅仅使用mycommand
。正如在Hendrik Jan Thomassen 的演讲,最初的 Unix 命令很短,因为旧 PDP-11 终端上的按键很难按。现在我们不必担心这个问题,而且如果您将该命令放在脚本中,这意味着您不必重新输入它。
关于 rm --dry-run
GNU Coreutils 以以下特点而闻名拒绝特征已经具有某些类似的实现或可以通过与其他实用程序结合来实现;例如df
在--no-header
标志被拒绝因为可以使用sed
或其他可以删除第一行文本的实用程序来完成。这是有道理的。
目前为止rm
,已经存在-i
用于交互的标志,因此它应该提示用户。另一种常用技术是使用echo
而不是任何命令进行试运行。因此,--dry-run
可以通过以下方式实现该标志:
# Prompts for y/n answer every time
rm -i ./*
# Automates answering "n"
for f in ./*; do rm -i "$f" <<< "n"; done
# or for non-bash shells:
for f in ./*; do echo "n" | rm -i "$f"; done
# prints the command that would be executed
echo rm "$file"
所有这些方法都可以与我之前提到的方法相结合——用自定义函数或脚本包裹原始命令。例如:
saferm(){
case "$@" in
*--dry-run*) echo rm "$@";;
*) rm "$@";;
}