我想遍历从echo $VARIABLE
命令中获得的路径列表。
例如:
echo $MANPATH
将返回
/usr/lib:/usr/sfw/lib:/usr/info
所以这是三个不同的路径,每个路径用冒号分隔。我想遍历这些路径中的每一个。有没有办法做到这一点?谢谢。
感谢到目前为止的所有回复,看来我实际上根本不需要循环。我只需要一种取出冒号的方法,这样我就可以ls
在这三个路径上运行一个命令。
您可以设置内部字段分隔符:
( IFS=:
for p in $MANPATH; do
echo "$p"
done
)
我使用了一个子外壳,因此 IFS 的更改不会反映在我当前的外壳中。
在 Bash 中,执行此操作的规范方法是read
适当地使用内置函数:
IFS=: read -r -d '' -a path_array < <(printf '%s:\0' "$MANPATH")
这是唯一强大的解决方案:将完全按照您的意愿进行操作:在分隔符上拆分字符串,:
并且对于空格、换行符和全局字符(如*
、[ ]
等)是安全的(与其他答案不同:它们都已损坏)。
在此命令之后,您将拥有一个数组path_array
,您可以在其上循环:
for p in "${path_array[@]}"; do
printf '%s\n' "$p"
done
您可以使用 Bash 的模式替换参数扩展来填充循环变量。例如:
MANPATH=/usr/lib:/usr/sfw/lib:/usr/info
# Replace colons with spaces to create list.
for path in ${MANPATH//:/ }; do
echo "$path"
done
注意:不要将替换扩展括在引号中。您希望 MANPATH 中的扩展值被 for 循环解释为单独的单词,而不是单个字符串。
通过这种方式,您可以安全地通过$PATH
单个循环,而循环$IFS
内部或外部将保持不变。
while IFS=: read -d: -r path; do # `$IFS` is only set for the `read` command
echo $path
done <<< "${PATH:+"${PATH}:"}" # append an extra ':' if `$PATH` is set
您可以检查 的值$IFS
,
IFS='xxxxxxxx'
while IFS=: read -d: -r path; do
echo "${IFS}${path}"
done <<< "${PATH:+"${PATH}:"}"
输出将是这样的。
xxxxxxxx/usr/local/bin
xxxxxxxx/usr/bin
xxxxxxxx/bin
for p in $(echo $MANPATH | tr ":" " ") ;do
echo $p
done
这也可以在命令行上用 Python 解决:
python -c "import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]" echo {}
或作为别名:
alias foreachpath="python -c \"import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]\""
使用示例:
foreachpath echo {}
这种方法的优点是{}
会被每条路径连续替换。这可用于构造各种命令,例如列出$PATH
. 包括名称中带有空格的目录:
foreachpath 'for e in "{}"/*; do du -h "$e"; done'
这是一个通过为in$PATH
中的每个文件和目录创建符号链接来缩短变量长度的示例。这对日常使用没有用,但如果您在容器中收到错误消息,可能会很有用,因为使用完整作为命令行的一部分......$PATH
$HOME/.allbin
too many arguments
docker
bitbake
$PATH
mkdir -p "$HOME/.allbin"
python -c "import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]" 'for e in "{}"/*; do ln -sf "$e" "$HOME/.allbin/$(basename $e)"; done'
export PATH="$HOME/.allbin"
理论上,这也应该加快常规 shell 的使用和 shell 脚本,因为搜索每个执行的命令的路径更少。不过,这很hacky,所以我不建议任何人缩短$PATH
这种方式。
不过,foreachpath
别名可能会派上用场。
IFS=:
arr=(${MANPATH})
for path in "${arr[@]}" ; do # <- quotes required
echo $path
done
...它确实会处理空格 :o) 但如果您有以下内容,还会添加空元素:
:/usr/bin::/usr/lib:
...然后索引 0,2 将为空(''),不能说为什么索引 4 根本没有设置
您可以使用 ${} 表示法中的 Bash for X 来完成此操作:
for p in ${PATH//:/$'\n'} ; do
echo $p;
done
结合以下想法:
代码:
PATHVAR='foo:bar baz:spam:eggs:' # demo path with space and empty
printf '%s:\0' "$PATHVAR" | while IFS=: read -d: -r p; do
echo $p
done | cat -n
输出:
1 foo
2 bar baz
3 spam
4 eggs
5
OP 的更新想要ls
生成的文件夹,并指出ls
只需要一个空格分隔的列表。
ls $(echo $PATH | tr ':' ' ')
很好很简单,应该很好地满足要求。