【问题标题】:How to loop over a list of directories containing wildcards in bash?如何在bash中循环包含通配符的目录列表?
【发布时间】:2017-04-08 22:40:16
【问题描述】:

假设我有一个包含几十年子目录的目录:

$ ls -d /very/long/path/*/
adir1/ adir2/ b2dir/ b3dir/ k101/ k102/ k103/ k104/ k220/ k221/ k222/ etc

我想循环选择将根据用户给出的答案“动态”定义的目录,其中包含通配符。例如(不起作用的代码):

$ cat my_script.sh

DATADIR="/very/long/path"
echo -n "Select dirs to involve: "
read dirlist
for DIR in "$dirlist"; do
  echo $DATADIR/$DIR 
  [do stuff]
  ...
done

需要的是以下内容:

$ ./my_script.sh
Select dirs to involve: a* k10?

/very/long/path/adir1
/very/long/path/adir2
/very/long/path/k101
/very/long/path/k102
/very/long/path/k103
/very/long/path/k104

有什么提示吗?

【问题讨论】:

  • 您的问题来自这样一个事实,即您的通配表达式在引号内,而引号(单引号或双引号)会阻止通配的发生。然而,您不能简单地删除引号,因为这可能会打开 $dirlist 扩展以进行分词,这是您不希望发生的(即包含空格的路径)。

标签: bash loops wildcard


【解决方案1】:

不确定这是否会遇到问题,但试一试:

DATADIR="/very/long/path"

read -r -p "Select dirs to involve: " -a dirs

cd $DATADIR

for dir in ${dirs[@]}
do
    echo "$dir"
done

不加引号的数组允许 glob 扩展。

更新:双循环允许使用目录位置

DATADIR="/very/long/path"

read -r -p "Select dirs to involve: " -a dirs

for item in "${dirs[@]}"
do
  for dir in "$DATADIR/"$item
  do
    echo "$dir"
  done
done

【讨论】:

  • 它有效。但是,我不知道cd 的限制有多大
  • 使用 cd - 可以轻松返回到之前的位置。否则,您可以将项目放在用逗号分隔的花括号中,以获得与附加到前面的位置相同的位置。
  • 没有cd 我不能将$DATADIR 传递给echo,因为带有花括号的$dirs 扩展拆分并且只有第一项(即adir1, adir2)被正确列出。跨度>
【解决方案2】:

一种可能的解决方案是使用find

#!/bin/bash
DATADIR="/very/long/path"
echo -n "Select matching expression: "
IFS= read -r dirlist
while IFS read -r -d '' DIR; do
  echo "$DIR"
  [do stuff]
  ...
done < <(find "$DATADIR" -path "$dirlist" -print0)

我建议您阅读 find 的联机帮助页,因为匹配会消耗掉斜线,并且可能与您习惯使用 shell globbing 时不同。

请注意,使用-print0read -d'' 可以确保处理具有有趣名称(空格、换行符)的文件没有问题。

如果您希望能够同时处理多个表达式输入,则必须执行以下操作:

#!/bin/bash
DATADIR="/very/long/path"
echo -n "Select matching expression: "
IFS= read -r -a dirlist_array
for dirlist in "${dirlist_array[@]}" ; do
  while IFS read -r -d '' DIR; do
    echo "$DIR"
    [do stuff]
    ...
  done < <(find "$DATADIR" -path "$dirlist" -print0)
done

【讨论】:

  • ./my_script.sh: line 9: syntax error near unexpected token &lt;' ./my_script.sh: line 9: done &lt; &lt;(find "$DATADIR" -path "$dirlist" -print0)' 我错过了什么吗?
  • @trian 奇怪,我在 shellcheck.net 上检查过...我没想到会出现这样的问题。您是否在内循环中添加了任何代码?你的 shell 是 Bash,如果是,是什么版本?
  • @trian 听起来您正在使用sh scriptname 运行脚本。如果是这样,您应该停止这样做(这是错误的,因为它可能导致脚本以不良方式发生故障)。 ./file 将自动使用正确的解释器,或者您也可以使用 bash file,因为 shebang 说 #!/bin/bash
  • @thatotherguy, @Fred,: 这个消息出现是因为我的 shebang 是 /bin/sh(虽然它是 bash 的别名)。将其更改为 /bin/bash 后,我得到:IFS: command not found
  • @trian 这一次听起来你写的是IFS = read ...而不是IFS= read。请尝试复制粘贴而不是徒手书写。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-04
  • 1970-01-01
  • 1970-01-01
  • 2013-04-03
  • 1970-01-01
  • 2011-04-15
  • 2010-10-15
相关资源
最近更新 更多