web-dev-qa-db-ja.com

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;

開始ディレクトリを定義しても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.
3
Curious Sam

for出力に対してfindループを使用することは、せいぜいアンチパターンです。 BashFAQ/001-ファイル(データストリーム、変数)を行ごと(および/またはフィールドごと)に読み取るにはどうすればよいですか? を参照してください。 whileコマンドを使用して、以下のようにreadループを使用します。以下のコマンドは、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

または、パイプラインの使用を完全に避け、プロセス置換を行います

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

Web ShellCheck は、上記の2つのスニペットのいずれについても問題を報告しません。

7
Inian

問題は、シェルチェックが正確に伝えていることです。forの出力を反復するfindループ、または同様のコマンドは壊れやすいものです。例えば:

$ ls
'a file with spaces' 

$ for file in $(find . ); do    echo "$file"; done
.
./a
file
with
spaces

安全な方法は、find-execを使用することです。

$ find . -exec echo  {} \;
.
./a file with spaces

または、whileループを使用するには:

$ find . -print0 | while IFS= read -r -d '' file; do echo "$file"; done
.
./a file with spaces
11
terdon