Bash

管道查找到 xargs 在終端中有效,但在 shell 腳本中無效

  • May 3, 2022

我正在嘗試編寫一個 Bash shell 腳本,它將目前目錄中的所有文件(減去一些例外)複製到另一個目錄中。該腳本建構一個命令,將其儲存在一個變數中,然後執行它。這是令人困惑的部分:當它建構的命令在 shell 腳本中執行時,它會失敗並顯示消息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

所有文件或文件夾的名稱中都沒有空格,也沒有任何特殊字元(下劃線和句點除外)。

因此,在@KamilMaciorowski 連結的答案中,我了解到 Bash 在執行命令的字元串中對管道的處理方式不同。$cmd我通過將線路更改為解決了這個問題,eval "$cmd"現在效果很好!

請注意,eval可能會導致程式碼注入問題,但這與此特定腳本無關。

您對將列表載入到命令有一個好主意,但是有更好的方法來組合變數和命令。

@KamilMaciorowski 在這裡提供了一些很好的背景資訊,但您可能仍在四處尋找更明確的答案。通過在此處閱讀更多內容,您可以看到一個很好的範例,用於printf將數組格式化為find命令。

在您的情況下,這將是這樣的:

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

引用自:https://unix.stackexchange.com/questions/701210