find: 'count=1': そのようなファイルまたはディレクトリはありません

find: 'count=1': そのようなファイルまたはディレクトリはありません

以前のコード:

total=`ls -Rp rootfs | wc -l`
count=0

変数に単純な加算を割り当てる場合:

sudo find rootfs -exec cp -d -- "{}" "/media/$USER/{}" 2> /dev/null \; -exec sync \; -exec count=$((count+1)) \; -exec echo -en "\rcopiati: $count/$total" \;

次のような結果になります:

find: ‘count=1’: No such file or directory

また、exec を実行すると:

sudo find rootfs -exec cp -d -- "{}" "/media/$USER/{}" 2> /dev/null \; -exec sync \; -exec count=1 \; -exec echo -en "\rcopiati: $count/$total" \;

同じエラーが発生します。なぜでしょうか?

コピーされたファイルごとに、カウンターが必要です: 1/13444、これは 2/13444、3/13444 などに更新されます...

編集:

方法は見つかりましたが、隠しファイルが表示されません。for ループで隠しファイルが表示されるようにするにはどうすればよいでしょうか?

#!/bin/bash
copysync() {
    countfiles() {
        for f in $1/*; do
            if [ -d "$f" ]; then
                countfiles "$f"
            else
                if [ "${f: -2}" != "/*" ]; then
                    total=$((total+1))
                fi
            fi
        done
    }
    recursivecp() {
        for f in $1/*; do
            if [ -d "$f" ]; then
                mkdir -p "/media/$USER/$f"
                recursivecp "$f"
            else
                if [ "${f: -2}" != "/*" ]; then
                    sudo cp -a "$f" "/media/$USER/$f"
                    sudo sync
                    count=$((count+1))
                    echo -en "\rCopied: $((count*100/total))%"
                fi
            fi
        done
    }
    total=0
    countfiles $1
    count=0
    recursivecp $1
}
copysync rootfs

答え1

count=$((count+1))実行前にシェルが拡張されますfind

次に、find引数を-execコマンドとして実行しようとします。これはプログラムまたはスクリプトである必要があり、シェル組み込みまたは変数割り当て用のシェル構文にすることはできません。

find見つかったファイルのカウントは、 の新しいプロセスを開始するためこの方法では機能しません-exec。そのため、変数割り当ての結果は親シェルでは利用できません。

find見つかったファイルごとに1行ずつ出力し、その出力を にパイプすることを提案しますwc -l。たとえば、

find rootfs -exec cp -d -- "{}" "/media/$USER/{}" \; -exec sync \; -print|wc -l

ファイルをコピーしながら出力を取得するには、次のようなものを使用できます。

find rootfs|while IFS= read -r file
do
    cp -d -- "$file" "/media/$USER/$file"
    sync
    count=$((count+1))
    echo -en "\rcopiati: $count/$total"
done

備考:

これは、改行文字 (およびその他の特殊文字) を含むファイル名では機能しません。

サブディレクトリが含まれている場合、スクリプトは動作しない可能性があります。この問題を回避するには、rootfsこのケースを処理するか、findのオプション-maxdepthとを使用する必要があります。-type f

答え2

で各コマンドを実行しようとしているようです。 は外部コマンドのみを実行する-execため、一般的なケースではこれは機能しません。-exec

代わりに、単一のインライン スクリプトを呼び出し、findそのスクリプト内のループのジェネレーターとして動作させます。

find rootfs -type f -exec sh -c '
    for pathname do
        cp -d "$pathname" "/media/$USER" &&
        echo . &&
        sync
    done' sh {} + | wc -l

これにより、ディレクトリ内またはその下にあるすべての通常ファイルが検索されますrootfs。これらのファイルのバッチの場合、短いインラインsh -cスクリプトが呼び出されます。このスクリプトは、各ファイルを指定されたディレクトリにコピーし、正常にコピーされたファイルごとにドットと改行を出力し、を呼び出しますsync

は、wc -l出力されたドットの数をカウントし、この数を報告します。パス名に改行文字が埋め込まれている場合、このカウントは誤解を招く可能性があるため、パス名自体はカウントしません。

を使用せずにfind、例えば次のように実行できますbash

shopt -s globstar dotglob nullglob

for pathname in rootfs/**/*; do
    [[ ! -f $pathname ]] && continue
    cp -d "$pathname" "/media/$USER" &&
    echo . &&
    sync
done | wc -l

**これは、シェル オプションが設定されている場合、サブディレクトリまで一致する globを含む globbing パターンを使用します。また、隠し名前を表示できるようにglobstar設定し、パターンが何にも一致しない場合はループをまったく実行しないようにシェル オプションを設定しました。dotglobnullglob

同じことですが、カウンターが付いています:

shopt -s globstar dotglob nullglob

count=0
for pathname in rootfs/**/*; do
    [[ ! -f $pathname ]] && continue
    cp -d "$pathname" "/media/$USER" &&
    count=$(( count + 1 ))
    sync
done
printf 'count=%d\n' "$count"

関連情報