即使给定了开始搜索的路径,shellcheck 也会警告 find 输出上的循环

Cur*_*Sam 3 bash find shellcheck

Ubuntu 16.04

#!/bin/bash

site="hello"
wDir="/home/websites/${site}/httpdocs/"

for file in $(find "${wDir}" -name "*.css")
do
   echo "$file";
done
exit 0;
Run Code Online (Sandbox Code Playgroud)

即使我定义了开始目录,shellcheck 也会警告我,但脚本工作得很好。

root@me /scripts/ # shellcheck test.sh

In test.sh line 6:
for file in $(find "${wDir}" -name "*.css")
            ^-- SC2044: For loops over find output are fragile. Use find -exec or a while read loop.
Run Code Online (Sandbox Code Playgroud)

ter*_*don 11

问题正是 shellcheck 告诉你的:for迭代输出find或类似命令的循环是脆弱的。例如:

$ ls
'a file with spaces' 

$ for file in $(find . ); do    echo "$file"; done
.
./a
file
with
spaces
Run Code Online (Sandbox Code Playgroud)

安全的方法是使用-execof find

$ find . -exec echo  {} \;
.
./a file with spaces
Run Code Online (Sandbox Code Playgroud)

或者使用while循环:

$ find . -print0 | while IFS= read -r -d '' file; do echo "$file"; done
.
./a file with spaces
Run Code Online (Sandbox Code Playgroud)


Ini*_*ian 7

使用for循环find输出充其量是一种反模式。请参阅BashFAQ/001 - 如何逐行(和/或逐字段)读取文件(数据流、变量)?为什么。whileread命令中使用如下循环。下面的命令find用 NULL 字节read分隔输出,并通过拆分该字节来读取命令,以便安全处理名称中包含特殊字符的所有文件(包括换行符)

#!/usr/bin/env bash

site="hello"
wDir="/home/websites/${site}/httpdocs/"

find "${wDir}" -name "*.css" -type f -print0 | while IFS= read -r -d '' file; do
    printf '%s\n' "$file"
done
Run Code Online (Sandbox Code Playgroud)

或者完全避免使用管道并进行流程替换

while IFS= read -r -d '' file; do
    printf '%s\n' "$file"
done< <(find "${wDir}" -name "*.css" -type f -print0)
Run Code Online (Sandbox Code Playgroud)

Web ShellCheck不会报告上述两个片段中的任何一个的任何问题。

  • 海事组织,`| while` 也是反模式...... `find` 已经有 `-exec` 可以正确处理文件名...... (3认同)