【问题标题】:Possible to turn 10 similar functions into a for loop?可以将 10 个类似的函数变成一个 for 循环吗?
【发布时间】:2016-04-03 21:10:03
【问题描述】:

我正在尝试将信息从我的工作区传递到另一个命令,并且因为每个工作区都包含相同的信息,只有不同的数字来标识它,所以我编写了 10 个函数,唯一的区别是一些变量名称中的一个字符.我觉得这可以大大简化,但我不知道如何让任何类型的循环在我的情况下工作。

这里是我的包含 10 个函数的脚本:

#!/bin/bash

# Include config file.
. $(dirname $0)/config

getWorkspaceInfo(){
    filledWorkspaces=$(i3-msg -t get_workspaces | grep -Po '"'"name"'"\s*:\s*"\K([^"]*)')
    currentWorkspace=$(i3-msg -t get_outputs | sed 's/.*"current_workspace":"\([^"]*\)".*/\1/')
}

# Determine the status of each workspace. Current is green, unfocused is white, empty is grey.
workspace1(){
    if [[ ${currentWorkspace} -eq 1 ]]; then
        workspace1Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "1") == "" ]]; then
        workspace1Color=${grey}
    else
        workspace1Color=${foreground}
    fi

    echo "%{F${workspace1Color}}${workspace1Name}"
}

workspace2(){
    if [[ ${currentWorkspace} -eq 2 ]]; then
        workspace2Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "2") == "" ]]; then
        workspace2Color=${grey}
    else
        workspace2Color=${foreground}
    fi

    echo "%{F${workspace2Color}}${workspace2Name}"
}

workspace3(){
    if [[ ${currentWorkspace} -eq 3 ]]; then
        workspace3Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "3") == "" ]]; then
        workspace3Color=${grey}
    else
        workspace3Color=${foreground}
    fi

    echo "%{F${workspace3Color}}${workspace3Name}"
}

workspace4(){
    if [[ ${currentWorkspace} -eq 4 ]]; then
        workspace4Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "4") == "" ]]; then
        workspace4Color=${grey}
    else
        workspace4Color=${foreground}
    fi

    echo "%{F${workspace4Color}}${workspace4Name}"
}

workspace5(){
    if [[ ${currentWorkspace} -eq 5 ]]; then
        workspace5Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "5") == "" ]]; then
        workspace5Color=${grey}
    else
        workspace5Color=${foreground}
    fi

    echo "%{F${workspace5Color}}${workspace5Name}"
}

workspace6(){
    if [[ ${currentWorkspace} -eq 6 ]]; then
        workspace6Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "6") == "" ]]; then
        workspace6Color=${grey}
    else
        workspace6Color=${foreground}
    fi

    echo "%{F${workspace6Color}}${workspace6Name}"
}

workspace7(){
    if [[ ${currentWorkspace} -eq 7 ]]; then
        workspace7Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "7") == "" ]]; then
        workspace7Color=${grey}
    else
        workspace7Color=${foreground}
    fi

    echo "%{F${workspace7Color}}${workspace7Name}"
}

workspace8(){
    if [[ ${currentWorkspace} -eq 8 ]]; then
        workspace8Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "8") == "" ]]; then
        workspace8Color=${grey}
    else
        workspace8Color=${foreground}
    fi

    echo "%{F${workspace8Color}}${workspace8Name}"
}

workspace9(){
    if [[ ${currentWorkspace} -eq 9 ]]; then
        workspace9Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "9") == "" ]]; then
        workspace9Color=${grey}
    else
        workspace9Color=${foreground}
    fi

    echo "%{F${workspace9Color}}${workspace9Name}"
}

workspace10(){
    if [[ ${currentWorkspace} -eq 10 ]]; then
        workspace10Color=${green}
    elif [[ $(echo ${filledWorkspaces} | grep -w "10") == "" ]]; then
        workspace10Color=${grey}
    else
        workspace10Color=${foreground}
    fi

    echo "%{F${workspace10Color}}${workspace10Name}"
}

# Pipe functions to the bar infinitely.
while true; do
    getWorkspaceInfo
    echo "%{c}$(workspace1)${separator}$(workspace2)${separator}$(workspace3)${separator}$(workspace4)${separator}$(workspace5)${separator}$(workspace6)${separator}$(workspace7)${separator}$(workspace8)${separator}$(workspace9)${separator}$(workspace10)"
done | lemonbar -g ${panelWidth}x${panelHeight}+${panelX}+${bottomPanelY} -f "${font}" -f "${iconFont}" -B "${background}" -F "${foreground}" -p -d  | \
    while true; do read line; eval $line; done &

这是我要导入的配置文件:

#!/bin/bash

# Outside sources
xres="$HOME/.Xresources"
i3config="$HOME/.config/i3/config"

# Fetch information from Xresources
background=$(cat ${xres} | grep -i background | tail -c 8)
foreground=$(cat ${xres} | grep -i foreground | tail -c 8)
black=$(cat ${xres} | grep -i color0 | tail -c 8)
grey=$(cat ${xres} | grep -i color8 | tail -c 8)
red=$(cat ${xres} | grep -i color9 | tail -c 8)
green=$(cat ${xres} | grep -i color10 | tail -c 8)
yellow=$(cat ${xres} | grep -i color11 | tail -c 8)
blue=$(cat ${xres} | grep -i color12 | tail -c 8)
magenta=$(cat ${xres} | grep -i color13 | tail -c 8)
cyan=$(cat ${xres} | grep -i color14 | tail -c 8)
white=$(cat ${xres} | grep -i color15 | tail -c 8)

# Fetch information from i3 config
gapSize=$(cat ${i3config} | grep -i "gaps inner" | awk '{print $3}')

# Workspace names -- independant from i3 config -- workspaces in i3 config should be named numbers 1-10.
workspace1Name="Web Browser"
workspace2Name="Terminal"
workspace3Name="Text Editor"
workspace4Name="Unspecified"
workspace5Name="Unspecified"
workspace6Name="Unspecified"
workspace7Name="Unspecified"
workspace8Name="Unspecified"
workspace9Name="Messenger"
workspace10Name="Music Player"

# Fonts
font="InputSans-10"
iconFont="FontAwesome"

separator="%{F$foreground}   |│|   "

# Panel size
screenWidth=$(xrandr | grep 'Screen 0'| awk '{print $8}')
screenHeight=$(xrandr | grep 'Screen 0' | awk '{print $10}' | tr -d ",")

panelHeight=$((${gapSize} * 2))
panelWidth=$((${screenWidth} - ${panelHeight}))
panelX=${gapSize}
topPanelY=${gapSize}
bottomPanelY=$((${screenHeight} - ${panelHeight} - ${gapSize}))

【问题讨论】:

  • 你的函数真的需要设置全局变量workspace1color吗?如--是否有一些后续代码,在调用函数后,需要使用函数设置的workspace1color
  • 不,脚本的最后一行——在所有函数的声明之后——简单地调用它们,然后通过管道输出。
  • 您可以节省大量缓慢的进程,避免无用地使用cat:red=$(grep -i color9 $xres | tail -c 8)。接下来,grep|awk 是一个反模式,因为 awk 内置了 grep:xrandr | awk '/Screen 0/ {print $8}'
  • @Jens,感谢您提供的信息。我刚开始使用 bash —— 和 Linux —— 所以希望我的使用会变得更好。

标签: linux bash shell sh


【解决方案1】:

嗯,最简单的解决方法是编写如下内容:

function all_10_workspaces () {
    local i
    for i in {1..10} ; do
        local workspaceNameVar="workspace${i}Name"
        local workspaceName="${!workspaceNameVar}"

        local color
        if (( currentWorkspace == 1 )) ; then
            color=$green
        elif grep -w -q "$i" <<< "$filledWorkspaces" ; then
            color=$foreground
        else
            color=$grey
        fi

        echo "%{F$color}$workspaceName"
    done
}

。 . .但是,您应该真正考虑使用数组。例如:

workspaceNames=(
    ''             # 0 (no such workspace)
    'Web Browser'  # 1
    Terminal       # 2
    'Text Editor'  # 3
    Unspecified    # 4
    Unspecified    # 5
    Unspecified    # 6
    Unspecified    # 7
    Unspecified    # 8
    Messenger      # 9
    'Music Player' # 10
)

然后,例如,工作区#7 被命名为"${workspaceNames[7]}",并且给定变量i,工作区#i 被命名为"${workspaceNames[i]}"

【讨论】:

  • 这很好用,但我一定误解了这个函数的结果。该脚本的重点是通过将信息传送到另一个程序来以图形方式显示每个工作区的名称。这当前循环遍历每个工作区名称并在最后一个显示它们。感谢您向我展示数组是如何工作的,在我编写的小脚本中还有许多其他情况,数组也很有用。如果我没有因询问错误信息而使您不感兴趣,那么我在问题中包含了整个脚本而不是一个函数。
  • 只是为了确保我理解这一点,您可以使用! 在变量中包含变量吗?以前我只是想做${workspace${i}Name}
  • @Wulfre: 如果foo 是一个值为bar 的变量,那么${!foo} 等价于${bar}。这称为间接扩展。见the Bash Reference Manual, §3.5.3 "Shell Parameter Expansion"
  • 我通过扩展你的两个想法解决了这个问题 - for 循环和数组。
【解决方案2】:

大概是这样的吧?

workspaceCount=10

while true; do
  # Output will look like "%{c}$(workspace1Color)${separator}$(workspace2Color)${separator}...."

  # This is what is sent before the first item in each line
  itemSep="%{c}"

  for i in {1..$workspaceCount}; do

    if [ ${currentWorkspace} -eq $i ]; then
      color="${green}"
    elif [[ $(echo ${filledWorkspaces} | grep -w "1") == "" ]]; then
      color="${grey}"
    else
      color="${foreground}"
    fi

    echo -n "${itemSep}${color}"
    itemSep="${separator}"

  done
  echo   # Send LF after all items

done

【讨论】:

  • 感谢您提供有关如何使分隔符起作用的想法。我为我的最终答案偷了这个想法。
【解决方案3】:

我想出了一种方法来使用 ruakh 和 Phil Freed 的想法以及我自己想出的东西来获得我想要的东西。这可能不是解决问题的最短或最有效的方法,但它比拥有 10 个单独的函数要短得多。

#!/bin/bash

# Include config file.
. $(dirname $0)/config

getWorkspaceInfo(){
    filledWorkspaces=$(i3-msg -t get_workspaces | grep -Po '"'"name"'"\s*:\s*"\K([^"]*)')
    currentWorkspace=$(i3-msg -t get_outputs | sed 's/.*"current_workspace":"\([^"]*\)".*/\1/')
}

# Determine the status of each workspace. Current is green, unfocused is white, empty is grey.
workspaces(){
    workspaces=""
    currentSeparator="${separator}"

    for i in {1..10} ; do
        if [[ ${currentWorkspace} -eq ${i} ]]; then
            color=${green}
        elif [[ $(echo ${filledWorkspaces} | grep -w "${i}") == "" ]]; then
            color=${grey}
        else
            color=${foreground}
        fi

        if [[ ${i} -eq 10 ]]; then
            currentSeparator=""
        fi

        workspaces+="%{F$color}${workspaceNames[i]}${currentSeparator}"
    done

    echo "${workspaces}"
}

# Pipe functions to the bar infinitely.
while true; do
    getWorkspaceInfo
    echo "%{c}$(workspaces)"
done | lemonbar -g ${panelWidth}x${panelHeight}+${panelX}+${bottomPanelY} -f "${font}" -f "${iconFont}" -B "${background}" -F "${foreground}" -p -d | \
    while true; do read line; eval $line; done &

尽可能简单地解释它的作用: 循环遍历所有 10 个工作区,将单个函数的输出添加到新变量的末尾。由于我不能再在每个函数调用之间添加分隔符,我只是将分隔符添加到 echo 的末尾,通过使用 for 循环确保没有分隔符添加到最后一个工作区,它将分隔符变量设置为 null。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-04
    • 1970-01-01
    • 2020-06-12
    • 1970-01-01
    • 2020-08-04
    • 2019-08-15
    • 2012-09-30
    相关资源
    最近更新 更多