谁能告诉我一个“选择”过滤器脚本,其工作原理如下所述?
我花了大约一个小时寻找一个简单的 bash 脚本/过滤器,它允许我通过管道输入值列表,并根据我在控制台所做的选择吐出其中的子集。我知道有用 C 编写的示例,但我想要一个可以在 Cygwin / Gitbash 等中使用的主要可移植的 bash 脚本。(上下文:我希望能够在某些子目录中运行某些命令,并且我想将选择分开要运行命令的目录,由要运行的命令选择。)
作为假设的用法示例:
$ echo "foo
> bar
> baz" | pick.sh
* Options:
* 1. foo
* 2. bar
* 3. baz
* Choices? 2 3
bar
baz
标记为 * 的行应该是脚本以交互方式让我选择要“挑选”哪些元素的位置,一旦我决定了第 2 行和第 3 行,它就会将它们发送到 STDOUT。
理想情况下,选择可以是空格分隔的数字(例如 2 3 4)、包含范围(例如 2-4)的组合。或者甚至可能足够奇特,可以使用某种自动完成功能,允许键入项目本身的前几个字母。
好吧,就是这样,我认为总的来说,这将是一个非常有用的 bash 管道过滤器!
(感谢您阅读到目前为止..)
答案1
使用行说明符的自我演示示例sed
(其中N,M
表示第 N 行到 M 行):
$ ./pick.sh < ./pick.sh
Lines:
1 #!/usr/bin/env bash
2
3 set -o errexit -o nounset -o noclobber
4
5 trap 'rm --force --recursive "$working_directory"' EXIT
6 working_directory="$(mktemp --directory)"
7 input_file="${working_directory}/input.txt"
8
9 cat > "$input_file"
10
11 echo 'Lines:'
12 cat --number "$input_file"
13
14 IFS=' ' read -p 'Choices: ' input < /dev/tty
15 lines=($input)
16
17 sed --quiet "$(printf '%sp;' "${lines[@]}")" "$input_file"
Choices: 1 5,7 17
#!/usr/bin/env bash
trap 'rm --force --recursive "$working_directory"' EXIT
working_directory="$(mktemp --directory)"
input_file="${working_directory}/input.txt"
sed --quiet "$(printf '%sp;' "${lines[@]}")" "$input_file"
基本上,将标准输入保存到临时文件,打印带有行号的文件,提示输入范围,并将输入范围传递给sed
打印每个范围。
此方法的一个怪癖是,行将按照它们在文件中出现的顺序打印,而不是您指定的顺序:
…
Choices: 3 1
#!/usr/bin/env bash
set -o errexit -o nounset -o noclobber
如果您确实需要输入顺序,那么循环起来会很简单lines
,尽管这当然效率较低。
该脚本假设您有GNU cat
、sed
等已安装。如果您使用 BSD 工具,命令标志将会不同。