【问题标题】:Ignore empty elements of bash indexed array忽略 bash 索引数组的空元素
【发布时间】:2013-11-08 18:10:25
【问题描述】:

我正在过滤PATH 变量,以便删除某些元素(在下面的示例中,它是包含字符串x86 的元素;实际上我正在寻找字符串site-packages):

$ echo $(IFS=:;arr=($PATH);echo "${arr[*]//*x86*}")
/usr/local/bin:/usr/bin:/cygdrive/c/Program Files/Common Files/Microsoft Shared/Windows Live::/cygdrive/c/Program Files/Lenovo Fingerprint Reader:::/cygdrive/c/Program Files/Intel/iCLS Client:/cygdrive/c/Windows/system32:/cygdrive/c/Windows:/cygdrive/c/Windows/System32/Wbem:/cygdrive/c/Windows/System32/WindowsPowerShell/v1.0:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/DAL:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/IPT:::::/cygdrive/c/Program Files/Intel/WiFi/bin:/cygdrive/c/Program Files/Common Files/Intel/WirelessCommon:/cygdrive/c/Program Files/Common Files/Lenovo:::/cygdrive/c/SWTOOLS/ReadyApps:::::/usr/lib/lapack

这很好用,除了所有被清零的元素仍然存在,但是是空的。我想最终消除这些元素,并且我不想使用 bash 以外的任何东西来做到这一点(我知道我可以使用 tr,但出于可移植性的原因,我更喜欢仅使用 bash 的解决方案)。

这是基于 tr 的解决方案:

echo $(IFS=:;arr=($PATH);echo "${arr[*]//*x86*}" | tr -s :)

更新:我使用数组是因为我希望在路径元素中面对空格(或冒号以外的任何其他内容)时保持稳健。

【问题讨论】:

    标签: arrays bash


    【解决方案1】:

    你必须更明确地说:

    PATH=$(
      IFS=:
      new=()
      for p in $PATH; do
        [[ $p != *x86* ]] && new+=("$p")
      done
      echo "${new[*]}"
    )
    

    它更冗长,但根据要求正确且仅限 bash

    【讨论】:

    • 谢谢。比我在过滤后构建新数组的方法更简洁。
    【解决方案2】:

    这不需要显式循环,但可能有点脆弱。它使用退格来“取消写入”要删除的目录前面的冒号,如果删除了PATH 中的第一个或最后一个目录,则需要特殊处理。

    echo $(IFS=:;
           arr=($PATH);
           # When finally echoed, any \b character will remove
           # the preceding colon from the output.
           new="${arr[*]//*x86*/$'\b'}";
           # Remove :\b if last directory was removed
           new=${new%:$'\b'};
           # Remove \b: if first directory was removed
           echo "${new#$'\b':}")
    

    【讨论】:

    • 这是一个有趣的方法。谢谢!
    【解决方案3】:

    这是一个使用循环构建连续数组的版本:

    $ echo $(IFS=:;arr=($PATH);sqarr="${arr[*]//*x86*}";declare -a finalarr; for item in $sqarr; do [[ $item ]] && finalarr+=("$item"); done; echo "${finalarr[*]}")
    /usr/local/bin:/usr/bin:/cygdrive/c/Program Files/Common Files/Microsoft Shared/Windows Live:/cygdrive/c/Program Files/Lenovo Fingerprint Reader:/cygdrive/c/Program Files/Intel/iCLS Client:/cygdrive/c/Windows/system32:/cygdrive/c/Windows:/cygdrive/c/Windows/System32/Wbem:/cygdrive/c/Windows/System32/WindowsPowerShell/v1.0:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/DAL:/cygdrive/c/Program Files/Intel/Intel(R) Management Engine Components/IPT:/cygdrive/c/Program Files/Intel/WiFi/bin:/cygdrive/c/Program Files/Common Files/Intel/WirelessCommon:/cygdrive/c/Program Files/Common Files/Lenovo:/cygdrive/c/SWTOOLS/ReadyApps:/usr/lib/lapack
    

    跨多行:

    $(
      IFS=:
      arr=($PATH)
      sqarr="${arr[*]//*x86*}"
      declare -a finalarr
      for item in $sqarr; do 
          [[ $item ]] && finalarr+=("$item")
      done 
      echo "${finalarr[*]}"
    )
    

    【讨论】:

      【解决方案4】:

      这应该适用于 假设 PATH 成分不包含空格,因此肯定比其他解决方案更脆弱。空数组元素在arr2赋值点被丢弃

      echo $(IFS=:;arr=($PATH);unset IFS;arr2=(${arr[@]//*x86*});IFS=:;echo "${arr2[*]}")
      

      【讨论】:

      • 谢谢。我专门使用数组是因为我想在面对空间时保持健壮。很抱歉没有提到这一点。
      猜你喜欢
      • 2018-04-18
      • 2021-12-25
      • 2020-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-13
      相关资源
      最近更新 更多