Bash while 循环使用 IFS 从以冒号分隔的路径列表中读取

Gre*_*bet 5 shell bash string

我正在尝试编写一个 bash 函数,其行为类似于where.bashrc 中的内置函数tcsh。在tcsh, 中where列出所有内置函数、别名和PATH具有给定名称的可执行文件的绝对路径,即使它们被隐藏,例如

tcsh> where tcsh
/usr/bin/tcsh
/bin/tcsh
Run Code Online (Sandbox Code Playgroud)

作为其中的一部分,我想遍历 中的所有内容$PATH并查看是否存在具有适当名称的可执行文件。

以下 bash 代码段旨在遍历以冒号分隔的路径列表并打印每个组件后跟一个换行符,但是,它似乎只是$PATH在一行上打印了所有内容的全部内容

#!/bin/bash
while IFS=':' read -r line; do
    printf "%s\n" "$line"
done <<< "$PATH"
Run Code Online (Sandbox Code Playgroud)

正如现在站立,bash where并且./where只是打印/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

那么,如何设置我的 while 循环,以便循环变量的值依次是冒号分隔的路径列表的每个段?

Sté*_*las 7

read用于IFS分隔它读取的行中的单词,read直到第一次出现其中的任何字符时它才会告诉读取。

IFS=: read -r a b
Run Code Online (Sandbox Code Playgroud)

会读一行,第一前把部分:$a,并在休息$b

IFS=: read -r a
Run Code Online (Sandbox Code Playgroud)

会将整行(其余的)放入$a(除非该行仅包含一个:并且它是该行的最后一个字符)。

如果你想读到第一个:,你可以使用read -d:( ksh93, zshor bashonly)代替。

printf %s "$PATH" | while IFS= read -rd: dir || [ -n "$dir" ]; do
  ...
done
Run Code Online (Sandbox Code Playgroud)

(我们没有使用,<<<因为它会添加一个额外的换行符)。

或者您可以使用标准分词:

IFS=:; set -o noglob
for dir in $PATH""; do
  ...
done
Run Code Online (Sandbox Code Playgroud)

现在要注意一些警告:

  • $PATH组件表示当前目录。
  • $PATH表示当前目录(即,$PATH包含一个作为当前目录的组件,因此while read -d:在这种情况下循环将是错误的)。
  • //file/file某些系统上的相同,因此不需要,因此如果$PATH包含/,则需要小心诸如$dir/$file.
  • 设置的$PATH 表示将使用默认搜索路径,它与设置不同,但 $PATH 为空。

现在,如果它只是等效于tcsh/zshwhere命令,则可以使用bash's type -a

更多阅读: