我是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,否则它说不允许执行,有人知道为什么吗?提前致谢:)
几个建议:
-
无妨双引号变量
cp "$FILE" "$3" # prevents wordsplitting, helps you filenames with spaces
-
for
语句失败的根本原因 - 语法错误 - 它应该是:for FILE in ls "$1";
-
但是,永远不要解析
ls
输出。检查 [ 这个 ]。for FILE in ls "$1"; #drastic
-
代替步骤 2 中的
for-loop
,请使用find-while-read
组合:find "$1" -type f -print0 | while read -rd'' filename #-type f for files do #something with $filename done
- 为脚本使用小写变量名称,因为大写变量是为系统保留的。检查[这个]。
- 使用 [ 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 中,但它们将再次被复制。