パイプによるxargsの検索は端末では機能しますが、シェルスクリプトでは機能しません。

パイプによるxargsの検索は端末では機能しますが、シェルスクリプトでは機能しません。

現在のディレクトリ内のすべてのファイル(一部の例外を含む)を別のディレクトリにコピーするBashシェルスクリプトを作成しようとしています。スクリプトはコマンドを作成して変数に保存して実行します。混乱した部分は次のとおりです。ビルドされたコマンドがシェルスクリプトで実行されると、「find: paths must precede expression: `|xargs'前のスペースを削除するとわかります|」というメッセージで失敗しますfind: unknown predicate `-i'。しかし、ビルドして実行するように指示するとecho正しく動作します!もっと奇妙なことは、echo "$cmd"|bash同じエラーメッセージで失敗することです!

スクリプト( synchronize.sh):

#! /bin/bash

EXCLUDED_FILES=(folder1 file.txt synchronize.sh)
FLAGS='-r'
PROJECT_NAME=project

TARGET_DIR=$HOME/Documents/IDE/$PROJECT_NAME/assets
cmd='find ./* -maxdepth 0'
cmd_end="|xargs -i cp -r {} -t $TARGET_DIR"

for file in ${EXCLUDED_FILES[@]}
do
    cmd+=" ! -name \"$file\""
done

cmd+=$cmd_end

$cmd               #Running the command directly fails
#echo  $cmd        #Yet copying and pasting the output of this command will work just fine
#echo "$cmd"|bash  #Though this inexplicably fails, with the same message as just $cmd

ファイルまたはフォルダ名には、スペースや特殊文字(アンダースコアとピリオドを除く)はありません。

答え1

したがって、@KamilMaciorowskiがリンクした回答で、Bashはコマンドが実行される文字列でパイプを異なる方法で処理することに気づきました。配線を変えて問題を解決しましたが、$cmdeval "$cmd"はうまくいきます!

コード挿入の問題が発生する可能性がありますが、evalこれはこの特定のスクリプトとは関係ありません。

答え2

コマンドにリストをロードする方法については良いアイデアがありますが、変数とコマンドを組み合わせるより良い方法があります。

@KamilMaciorowskiはここに良い背景情報を提供しましたが、それでもより確実な答えを探しているかもしれません。ここで詳細を読むと、printf配列をコマンドとしてフォーマットする良い例がわかります。find

あなたの場合は次のようになります。

find ./* -maxdepth 0 $(printf "! -name %s " $EXCLUDED_FILES) -exec cp -r {} $TARGET_DIR \;

関連情報