在 Bash 中循环遍历路径变量的元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/11655770/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Looping through the elements of a path variable in Bash
提问by tim tran
I want to loop through a path list that I have gotten from an echo $VARIABLEcommand.
我想遍历从echo $VARIABLE命令中获得的路径列表。
For example:
例如:
echo $MANPATHwill return
echo $MANPATH将返回
/usr/lib:/usr/sfw/lib:/usr/info
/usr/lib:/usr/sfw/lib:/usr/info
So that is three different paths, each separated by a colon. I want to loop though each of those paths. Is there a way to do that? Thanks.
所以这是三个不同的路径,每个路径都用冒号分隔。我想遍历每条路径。有没有办法做到这一点?谢谢。
Thanks for all the replies so far, it looks like I actually don't need a loop after all. I just need a way to take out the colon so I can run one lscommand on those three paths.
感谢到目前为止的所有回复,看来我实际上根本不需要循环。我只需要一种去掉冒号的方法,这样我就可以ls在这三个路径上运行一个命令。
采纳答案by Todd A. Jacobs
You can use Bash's pattern substitution parameter expansionto populate your loop variable. For example:
您可以使用 Bash 的模式替换参数扩展来填充循环变量。例如:
MANPATH=/usr/lib:/usr/sfw/lib:/usr/info
# Replace colons with spaces to create list.
for path in ${MANPATH//:/ }; do
    echo "$path"
done
Note: Don't enclose the substitution expansion in quotes. You want the expanded values from MANPATH to be interpreted by the for-loop as separate words, rather than as a single string.
注意:不要用引号将替换扩展括起来。您希望 for 循环将来自 MANPATH 的扩展值解释为单独的单词,而不是单个字符串。
回答by choroba
You can set the Internal Field Separator:
您可以设置内部字段分隔符:
( IFS=:
  for p in $MANPATH; do
      echo "$p"
  done
)
I used a subshell so the change in IFS is not reflected in my current shell.
我使用了一个子 shell,所以 IFS 中的更改不会反映在我当前的 shell 中。
回答by gniourf_gniourf
The canonical way to do this, in Bash, is to use the readbuiltin appropriately:
在 Bash 中执行此操作的规范方法是read适当地使用内置函数:
IFS=: read -r -d '' -a path_array < <(printf '%s:for p in "${path_array[@]}"; do
    printf '%s\n' "$p"
done
' "$MANPATH")
This is the only robust solution: will do exactly what you want: split the string on the delimiter :and be safe with respect to spaces, newlines, and glob characters like *, [ ], etc. (unlike the other answers: they are all broken).
这是唯一可靠的解决方案:将不正是你想要什么:分裂的分隔字符串:和安全相对于空格,换行,并水珠的人物,如*,[ ]等(不像其他的答案:他们都打破)。
After this command, you'll have an array path_array, and you can loop on it:
执行此命令后,您将拥有一个 array path_array,您可以对其进行循环:
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
回答by Yi H.
In this way you can safely go through the $PATHwith a single loop, while $IFSwill remain the same inside or outside the loop.
通过这种方式,您可以安全地通过$PATH单个循环,而$IFS在循环内部或外部都将保持不变。
IFS='xxxxxxxx'
while IFS=: read -d: -r path; do
    echo "${IFS}${path}"
done <<< "${PATH:+"${PATH}:"}"
You can check the value of $IFS,
您可以检查的值$IFS,
xxxxxxxx/usr/local/bin
xxxxxxxx/usr/bin
xxxxxxxx/bin
and the output will be something like this.
输出将是这样的。
python -c "import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]" echo {}
Reference to another question on StackExchange.
参考StackExchange上的另一个问题。
回答by Alexander
This can also be solved with Python, on the command line:
这也可以用 Python 解决,在命令行上:
alias foreachpath="python -c \"import os,sys;[os.system(' '.join(sys.argv[1:]).format(p)) for p in os.getenv('PATH').split(':')]\""
Or as an alias:
或者作为别名:
foreachpath echo {}
With example usage:
使用示例:
foreachpath 'for e in "{}"/*; do du -h "$e"; done'
The advantage to this approach is that {}will be replaced by each path in succession. This can be used to construct all sorts of commands, for instance to list the size of all files and directories in the directories in $PATH. including directories with spaces in the name:
这种方法的优点是{}会被每条路径依次替换。这可用于构造各种命令,例如列出$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"
Here is an example that shortens the length of the $PATHvariable by creating symlinks to every file and directory in the $PATHin $HOME/.allbin. This is not useful for everyday usage, but maybe useful if you get the too many argumentserror message in a dockercontainer, because bitbakeuses the full $PATHas part of the command line...
下面是缩短了的长度,例如,$PATH通过创建符号链接到在每个文件和目录的变量$PATH中$HOME/.allbin。这对日常使用没有用,但如果您在容器中收到错误消息可能会很有用,因为使用完整作为命令行的一部分......too many argumentsdockerbitbake$PATH
PATHVAR='foo:bar baz:spam:eggs:'  # demo path with space and empty
printf '%s:1   foo
2   bar baz
3   spam
4   eggs
5   
' "$PATHVAR" | while IFS=: read -d: -r p; do
    echo $p
done | cat -n
This should also, in theory, speed up regular shell usage and shell scripts, since there are fewer paths to search for every command that is executed. It ispretty hacky, though, so I don't recommend that anyoneshorten their $PATHthis way.
从理论上讲,这也应该加快常规 shell 使用和 shell 脚本的速度,因为搜索每个执行的命令的路径更少。这是相当哈克,虽然,所以我不建议任何人缩短他们的$PATH这种方式。
The foreachpathalias might come in handy, though.
不过,foreachpath别名可能会派上用场。
回答by Walker Hale IV
Combining ideas from:
结合来自以下方面的想法:
code:
代码:
IFS=:
arr=(${MANPATH})
for path in "${arr[@]}" ; do # <- quotes required
   echo $path
done
output:
输出:
:/usr/bin::/usr/lib:
回答by Acid
for p in ${PATH//:/$'\n'} ; do
    echo $p;
done
... it does take care of spaces :o) but also adds empty elements if you have something like:
...它确实会处理空格 :o) 但如果您有以下内容,也会添加空元素:
for p in $(echo $MANPATH | tr ":" " ") ;do
    echo $p
done
... then index 0,2 will be empty (''), cannot say why index 4 isnt set at all
...然后索引 0,2 将为空(''),不能说为什么索引 4 根本没有设置
回答by Hunter McMillen
You can use Bash's for X in ${} notation to accomplish this:
您可以在 ${} 符号中使用 Bash 的 X 来完成此操作:
##代码##
