忽略bash索引数组的空元素

时间:2022-07-22 16:48:43

I'm filtering PATH variables, such that certain elements are deleted (in the example below, it's elements containing the string x86; in practice I'm looking for the string site-packages):

我正在过滤路径变量,以便删除某些元素(在下面的示例中,它是包含字符串x86的元素;在实践中,我正在查找字符串站点包):

$ 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

This works pretty well, except that all of the elements which have been zeroed out are still, there, but empty. I'd like to end up with those elements eliminated, and I don't want to use anything other than bash to do it (I know I can use tr, but for portability reasons I would strongly prefer a bash-only solution).

这很有效,除了所有被归零的元素都是空的。我希望最终消除这些元素,我不希望使用bash以外的任何东西来实现它(我知道我可以使用tr,但出于可移植性的原因,我强烈希望使用只有bash的解决方案)。

Here's the tr-based solution:

这是tr-based解决方案:

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

Update: I'm using arrays because I want to be robust in the face of spaces (or anything else other than colons) in the path elements.

更新:我使用数组是因为我想在路径元素的空间(或除冒号之外的任何东西)中保持健壮。

4 个解决方案

#1


3  

You'll have to be more explicit about it:

你必须更明确地说明:

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

It's more verbose, but correct and bash-only as requested

它更详细,但正确,并且只按要求

#2


2  

This doesn't require an explicit loop, but might be a bit fragile. It uses a backspace to "unwrite" the colon preceding a directory to remove, and it requires special handling if the first or last directory in PATH is removed.

这并不需要显式循环,但可能有点脆弱。它使用后置空间“取消”要删除的目录前面的冒号,如果删除路径中的第一个或最后一个目录,则需要进行特殊处理。

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


0  

Here's a version which builds up a contiguous array using a loop:

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

$ 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

Across multiple lines:

跨多行:

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

#4


0  

This should work with assuming PATH constituents do not contain spaces, so definitely more fragile than the other solutions. The empty array elements are discarded at the point of arr2 assignment

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

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

#1


3  

You'll have to be more explicit about it:

你必须更明确地说明:

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

It's more verbose, but correct and bash-only as requested

它更详细,但正确,并且只按要求

#2


2  

This doesn't require an explicit loop, but might be a bit fragile. It uses a backspace to "unwrite" the colon preceding a directory to remove, and it requires special handling if the first or last directory in PATH is removed.

这并不需要显式循环,但可能有点脆弱。它使用后置空间“取消”要删除的目录前面的冒号,如果删除路径中的第一个或最后一个目录,则需要进行特殊处理。

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


0  

Here's a version which builds up a contiguous array using a loop:

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

$ 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

Across multiple lines:

跨多行:

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

#4


0  

This should work with assuming PATH constituents do not contain spaces, so definitely more fragile than the other solutions. The empty array elements are discarded at the point of arr2 assignment

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

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