我试图编写一个简单的bash程序来在我的终端上执行,它将把一个目录中的所有文件复制到另一个目录中。这是我的第一个bash程序。这是我现在的文件:
#!/bin/bash
cd /Users/georgi/Loopback_projects/ESPC/common/models
for f in *.json
do
cp -v $f /Users/georgi/AndroidStudioProjects/ESPC_Retrofit/app/src/main/assets
done
当我在终端中像这样运行脚本时:
Chriss-iMac:georgi$ exportToAndroid.sh
上面写着-bash: exportToAndroid.sh: command not found
简短回答:
-
让你的脚本可执行:
chmod +x exportToAndroid.sh
-
运行:
./exportToAndroid.sh
长答:
当您在终端中输入内容时,字符串将被解析,切成单词,并且(除了重定向或环境变量或其他关键字)第一个单词将被理解为要执行的命令。如果shell将这个单词识别为函数或内置(我在这里忽略别名),那么它将使用给定的参数运行该函数或内置;但我们不是在这种情况下:exportToAndroid.sh
都不是。在这种情况下(因为这个单词不包含斜杠),shell将查看您的PATH
变量,以检查是否找到了一个名为exportToAndroid.sh
的文件(如果找到了,它将愉快地执行它);但在这里却找不到!(检查你的PATH
变量与echo "$PATH"
包含什么)。
如果不是给出一个没有斜杠的单词,而是给出一个带有斜杠的路径,那么shell将不会查看PATH
变量,而是尝试直接执行给定的文件。这就是为什么
./exportToAndroid.sh
。
如果您不想每次都在前面键入./
,可以这样做:
用
在主文件夹中创建一个bin/
目录mkdir ~/bin
- 将此目录添加到
PATH
变量中,如下所示:在.bashrc
文件的末尾,添加PATH=~/bin:$PATH
行(好吧,这不是将~/bin
添加到PATH
变量的可靠方法,但它应该是可以的), - 移动脚本到
~/bin
文件夹, 重新启动Bash会话;你可以检查你的
~/bin
文件夹出现在PATH
变量的第一个位置,echo "$PATH"
几个月后,你会意识到你的bin/
文件夹包含了很多你完全忘记了的无用的东西!这样做的好处是,您只需从任何目录中使用exportToAndroid.sh
调用脚本!
关于代码的注释:
在脚本中,在您
cd
之后,您应该始终检查cd
是否成功!一种可能性:cd /Users/georgi/Loopback_projects/ESPC/common/models || { echo "Can't cd"; exit 1; }
当使用变量展开时,除非你真的想要拆分单词和文件名展开(你很少想要这样!)事实上,这是非常罕见的做法,当我们希望发生这种情况时,我们总是写一行注释来解释我们的意图),你必须引用扩展:你的
cp
行最好写成cp -v "$f" /Users/georgi/AndroidStudioProjects/ESPC_Retrofit/app/src/main/assets
- 当使用glob时,如
for f in *.json
,您应该确保启用了shopt -s nullglob
(或shopt -s failglob
)。
#!/bin/bash
shopt -s nullglob
cd /Users/georgi/Loopback_projects/ESPC/common/models || { echo "Can't cd"; exit 1; }
for f in *.json; do
cp -v "$f" /Users/georgi/AndroidStudioProjects/ESPC_Retrofit/app/src/main/assets
done
但事实上,一个更简单、更有效的方法是这样做:
#!/bin/bash
shopt -s failglob
sourcedir=/Users/georgi/Loopback_projects/ESPC/common/models
targetdir=/Users/georgi/AndroidStudioProjects/ESPC_Retrofit/app/src/main/assets
cp -v "$sourcedir"/*.json "$targetdir"
这是更有效的,因为我们只调用cp
一次,而不是每个文件复制一次然而,如果有太多的文件要复制,这将失败…