通过在控制台中输入的选项从标准输入中选择选定的项目

通过在控制台中输入的选项从标准输入中选择选定的项目

谁能告诉我一个“选择”过滤器脚本,其工作原理如下所述?

我花了大约一个小时寻找一个简单的 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 catsed等已安装。如果您使用 BSD 工具,命令标志将会不同。

相关内容