如何在bash循环列表中转义空格?

前端之家收集整理的这篇文章主要介绍了如何在bash循环列表中转义空格?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个bash shell脚本循环通过某个目录的所有子目录(但不是文件)。问题是一些目录名称包含空格。

这里是我的测试目录的内容

$ls -F test
Baltimore/  Cherry Hill/  Edison/  New York City/  Philadelphia/  cities.txt

和循环通过目录的代码

for f in `find test/* -type d`; do
  echo $f
done

这里是输出

test/Baltimore
test/Cherry
Hill
test/Edison 
test/New
York
City
test/Philadelphia

樱桃山和纽约市被视为2或3个单独的条目。

我试着引用文件名,像这样:

for f in `find test/* -type d | sed -e 's/^/\"/' | sed -e 's/$/\"/'`; do
  echo $f
done

但无济于事。

有一个简单的方法来做到这一点。

下面的答案是伟大的。但是为了使这更复杂 – 我不总是想使用我的test目录中列出的目录。有时候,我想将目录名称作为命令行参数传递。

我采取了Charles的建议设置IFS,并提出以下:

dirlist="${@}"
(
  [[ -z "$dirlist" ]] && dirlist=`find test -mindepth 1 -type d` && IFS=$'\n'
  for d in $dirlist; do
    echo $d
  done
)

这工作很好,除非在命令行参数中有空格(即使这些参数被引用)。例如,调用这样的脚本:test.sh“Cherry Hill”“New York City”生成以下输出

Cherry
Hill
New
York
City
首先,不要这样做。最好的办法是正确使用find -exec:
# this is safe
find test -type d -exec echo '{}' +

另一个安全的方法是使用NUL终止列表,虽然这需要你找到支持-print0:

# this is safe
while IFS= read -r -d '' n; do
  printf '%q\n' "$n"
done < <(find test -mindepth 1 -type d -print0)

您还可以从find中填充数组,并稍后传递该数组:

# this is safe
declare -a myarray
while IFS= read -r -d '' n; do
  myarray+=( "$n" )
done < <(find test -mindepth 1 -type d -print0)
printf '%q\n' "${myarray[@]}" # printf is an example; use it however you want

如果你的find不支持-print0,你的结果是不安全的 – 如果文件存在包含换行符的名称(这是,是合法的),下面的行为将不会如所期望的:

# this is unsafe
while IFS= read -r n; do
  printf '%q\n' "$n"
done < <(find test -mindepth 1 -type d)

如果一个人不打算使用上述之一,第三种方法(在时间和内存使用方面效率较低,因为它在字分割之前读取子过程的整个输出)是使用IFS变量不包含空格字符。关闭globbing(设置-f)以防止包含glob字符的字符串,如[],*或?从扩展:

# this is unsafe (but less unsafe than it would be without the following precautions)
(
 IFS=$'\n' # split only on newlines
 set -f    # disable globbing
 for n in $(find test -mindepth 1 -type d); do
   printf '%q\n' "$n"
 done
)

最后,对于命令行参数的情况,你应该使用数组,如果你的shell支持它们(即它的ksh,bash或zsh):

# this is safe
for d in "$@"; do
  printf '%s\n' "$d"
done

将保持分离。注意,引用(和使用$ @而不是$ *)很重要。数组也可以通过其他方式填充,如glob表达式:

# this is safe
entries=( test/* )
for d in "${entries[@]}"; do
  printf '%s\n' "$d"
done

猜你在找的Bash相关文章