如何根据其他命令的输出动态构建 bash 对话框?

How to dynamically build a bash dialog from the output of an other command?

上下文

我正在尝试构建一个包含我的时间战士数据的对话框,这样我就可以直接 select 我要返回的内容而不是 timew s :ids filter_tag,然后 time cont @12 .

因此,首先我创建了试图填充对话框选项的数据集:

timew s :ids $(date -I -d'8 days ago') - $(date -I -d'tomorrow') |
    # most recent first, only the top 30 (4 additional lines are decoration)
    tac | head -n 34 |
    # format the whole thing as '1 "some label "' and so on
    sed -ne 's:.*@::p' |
    sed -e 's|\s\+[0-9]\+:.*| |g' -e's:\s\+: ":' -e's:\s*$:":' -e's:^: :'

这会生成如下所示的报告:

 1 "some_info, some_info"
 2 "some_info, some_info"
 3 "some_info, some_info"
 4 "some_info"
 5 "some_info, some_info"
 6 "some_info, some_info, some_info"
 7 "some_info, some_info"
 8 "some_info, some_info-some_info, some_info, some_info"
 9 "some_info, some_info"
 10 "some_info, some_info-some_info, some_info, some_info"
 11 "some_info, some_info"
 12 "some_info, some_info"
 13 "some_info"
 14 "some_info, some_info"
 14 "some_info, some_info"
 15 "some_info, some_info, some_info"
 16 "some_info, some_info, some_info, some_info, some_info, some_info"
 17 "some_info, some_info, some_info"
 18 "some_info"
 19 "some_info, some_info"
 20 "some_info"
 21 "some_info, some_info, some_info, some_info, some_info, some_info"
 22 "some_info, some_info"
 23 "some_info, some_info, some_info, some_info, some_info, some_info"
 24 "some_info, some_info45, some_info some_info some_info, some_info"
 25 "some_info"
 26 "some_info"
 27 "some_info, some_info, some_info"
 28 "some_info, some_info, some_info, some_info"
 29 "some_info, some_info, some_info"
 30 "some_info"

对话框脚手架

所以我找到了这个脚手架

#!/bin/bash

HEIGHT=15
WIDTH=40
CHOICE_HEIGHT=4
BACKTITLE="Backtitle here"
TITLE="Title here"
MENU="Choose one of the following options:"

OPTIONS=(1 "Option 1"
         2 "Option 2"
         3 "Option 3")

CHOICE=$(dialog --clear \
                --backtitle "$BACKTITLE" \
                --title "$TITLE" \
                --menu "$MENU" \
                $HEIGHT $WIDTH $CHOICE_HEIGHT \
                "${OPTIONS[@]}" \
                2>&1 >/dev/tty)

clear
case $CHOICE in
        1)
            echo "You chose Option 1"
            ;;
        2)
            echo "You chose Option 2"
            ;;
        3)
            echo "You chose Option 3"
            ;;
esac

问题

于是我天真地以为在前面的代码中用OPTIONS=( $(timew s :ids $(date -I -d'8 days ago') - $(date -I -d'tomorrow') | tac | head -n 34 | sed -ne 's:.*@::p' | sed -e 's|\s\+[0-9]\+:.*| |g' -e's:\s\+: ":' -e's:\s*$:":'))代替就可以了。但似乎不会那么容易考虑报价。我试图以各种方式破解它,包括在 while read 循环中和使用 Shell parameter expansion: ${variable@Q},以及其他可怕的东西,但没有找到任何可行的方法。

问题

如何使用我的 Timewarrior 输出正确填充对话框选项?

这应该能达到你想要的效果:

#!/bin/bash

HEIGHT=15
WIDTH=40
CHOICE_HEIGHT=4
BACKTITLE="Backtitle here"
TITLE="Title here"
MENU="Choose one of the following options:"

generate_options(){
    cat << EOF
Option 1
Option 2
Option 3
EOF
}

declare -a OPTIONS
count=1
while IFS= read -r line; do
    OPTIONS+=( $((count++)) "$line" )
done < <(generate_options)

CHOICE=$(dialog --clear \
                --backtitle "$BACKTITLE" \
                --title "$TITLE" \
                --menu "$MENU" \
                $HEIGHT $WIDTH $CHOICE_HEIGHT \
                "${OPTIONS[@]}" \
                2>&1 >/dev/tty)

clear
case $CHOICE in
        1)
            echo "You chose Option 1"
            ;;
        2)
            echo "You chose Option 2"
            ;;
        3)
            echo "You chose Option 3"
            ;;
esac

您只需要将 cat command 替换为您的命令(行首没有数字)。

所以这个问题的完整解决方案是:

#!/bin/bash

HEIGHT=40
WIDTH=80
CHOICE_HEIGHT=30
BACKTITLE="Timewarrior"
TITLE="Resume Selector"
MENU="Select task to resume"

generate_options(){
  # events of the last week, filtered by $@
  timew s :ids $(date -I -d'8 days ago') - $(date -I -d'tomorrow') "$@" |
    # most recent first, keep only a 60 entry buffer
    tac | head -n 60 |
    # format the whole thing as '1 some labels' and so on
    sed -ne 's:.*@::p' |
    sed -e 's|\s\+[0-9]\+:.*| |g' -e's:^: :' |
    # keep only 30 entries
    uniq | head -n 30
}

declare -a OPTIONS
while IFS= read -r line; do
  bid=$(echo "$line" | awk '{print }')
  peg=$(echo "$line" | sed 's:[0-9]\+\ \+::')
  # get ride of duplicates
  case "${OPTIONS[@]}" in  *"$peg"*) continue ;; esac
  OPTIONS+=( "$bid" "$peg" )
done < <(generate_options "$@")

CHOICE=$(dialog --clear \
                --backtitle "$BACKTITLE" \
                --title "$TITLE" \
                --menu "$MENU" \
                $HEIGHT $WIDTH $CHOICE_HEIGHT \
                "${OPTIONS[@]}" \
                2>&1 >/dev/tty)

clear
if [[ -z $CHOICE ]] ; then
  exit
fi
timew cont "@$CHOICE"