Bash 脚本:意外标记"完成"附近的语法错误



我是bash脚本的新手,我必须创建这个脚本,该脚本将3个目录作为参数,并在第三个目录中复制第一个目录中不在第二个中的所有文件。

我是这样做的:

#!/bin/bash
if [ -d $1 && -d $2 && -d $3 ]; then
    for FILE in [ ls $1 ]; do
        if ! [ find $2 -name $FILE ]; then
            cp $FILE $3
    done
else echo "Error: one or more directories are not present"
fi

当我尝试执行它时,我得到的错误是:"第 7 行:意外标记'完成'附近的语法错误"我真的不知道如何让它工作!另外,即使我使用 #!/bin/bash,我仍然必须在尝试执行时显式调用 bash,否则它说不允许执行,有人知道为什么吗?提前致谢:)

几个建议:

  1. 无妨双引号变量

    cp "$FILE" "$3" # prevents wordsplitting, helps you filenames with spaces
    
  2. for语句失败的根本原因 - 语法错误 - 它应该是:

    for FILE in ls "$1";
    
  3. 但是,永远不要解析ls输出。检查 [ 这个 ]。

     for FILE in ls "$1"; #drastic
    
  4. 代替步骤 2 中的for-loop,请使用find-while-read组合:

    find "$1" -type f -print0 | while read -rd'' filename #-type f for files
    do
    #something with $filename
    done
    
  5. 为脚本使用小写变量名称,因为大写变量是为系统保留的。检查[这个]。
  6. 使用 [ shellcheck ] 等工具提高脚本质量。

编辑

由于您已经提到输入目录仅包含文件,因此我的替代方法是

[[ -d "$1" && -d "$2" && -d "$3" ]] && for filename in "$1"/*
do
    [ ! -e "$2/${filename##*/}" ] && cp "$filename" "$3"
done

如果您对${filename##*/}感到困惑,请检查 [ shell 参数扩展 ]。


旁注:在 linux 中,虽然不鼓励使用像 file name 这样的非标准文件名并不少见。
友情提供:@chepner & @mklement0 他们的评论极大地改善了这个答案:)

您的脚本:

if ...; then
  for ...; do
    if ...; then
      ...
  done
else
  ...
fi

固定结构:

if ...; then
  for ...; do
    if ...; then
      ...
    fi       # <-- missing
  done
else
  ...
fi

如果您希望脚本可执行,请使其可执行:

$ chmod +x script.sh

请注意,脚本中还有其他问题。最好写成

dir1="$1"
dir2="$2"
dir3="$3"
for f in "$dir1"/*; do
  if [ ! -f "$dir2/$(basename "$f")" ]; then
    cp "$f" "$dir3"
  fi
done

并不完全正确:

for FILE in $(ls $1); do 
    < whatever you do here >
done

如果该文件夹中有一个这样的文件名,则该循环存在一个大问题:">我是一个带空格的文件名.txt"。与其尝试该循环,请尝试以下操作:

for FILE in "$1"/*; do
    echo "$FILE"
done

此外,您必须使用 fi 关闭每个 if 语句。

另一件事,如果您使用的是 BASH ( #!/usr/bin/env bash(,强烈建议在测试条件下使用双括号:

if [[ test ]]; then
    ...
fi

例如:

$ a='foo bar'
$ if [[ $a == 'foo bar' ]]; then
> echo "it's ok"
> fi
it's ok

但是,这:

$ if [ $a == 'foo bar' ]; then
> echo "it's ok"; 
> fi
bash: [: too many arguments

你已经忘记了fi在最里面的if之后。

此外,方括号和find都不能以这种方式工作。这个在我的电脑上执行您的脚本(就像现在一样(的意图:

#!/bin/bash
if [[ -d "$1" && -d "$2" && -d "$3" ]] ; then
    ls -1 "$1" | while read FILE ; do
        ls "$2/$FILE" >/dev/null 2>&1 || cp "$1/$FILE" "$3"
    done
else echo "Error: one or more directories are not present"
fi
请注意,在

单次运行后,当 $2 和 $3 引用不同的目录时,这些文件仍然不在 $2 中,因此下次运行脚本时,尽管它们已经存在于 $3 中,但它们将再次被复制。

相关内容

  • 没有找到相关文章

最新更新