加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-15 16:55:22 所属栏目:安全 来源:网络整理
导读:我有一个bash shell脚本循环通过某个目录的所有子目录(但不是文件)。问题是一些目录名称包含空格。 这里是我的测试目录的内容: $ls -F testBaltimore/ Cherry Hill/ Edison/ New York City/ Philadelphia/ cities.txt 和循环通过目录的代码: for f in `fin
我有一个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 '%qn' "$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 '%qn' "${myarray[@]}" # printf is an example; use it however you want

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

# this is unsafe
while IFS= read -r n; do
  printf '%qn' "$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 '%qn' "$n"
 done
)

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

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

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读