8

我需要在我的 shell 脚本中获取主目录,以便我的同事可以运行它。我的 shell 所做的非常简单,它只是将一些目录复制到另一个目录。我用过:

$HOME,
$(whoami)
即使这样:
ABSPATH=$(cd "$(dirname "$0")"; pwd),

但是当我像这样使用变量时:

DIR= $ABSPATH/文件夹/afolder/bfolder/

并运行它我收到这个:

/Users/theUser/Desktop/FusionTest.command:第14行:/Users/theUser/Desktop/folder/afolder/bfolder:是一个目录
复制到用法:cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] 源文件目标文件 cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory 注销
[过程完成]

我正在使用命令 cp -r 复制所有文件和目录。

为什么我失踪了?或者我该怎么做?

4

4 回答 4

8

正如错误消息所暗示-r的那样,递归复制的标志不正确。您想要的标志是-R(标志区分大小写)。至于主目录,$HOME应该始终有效。

于 2012-06-22T18:10:40.017 回答
5

在这里谈几件事:

  1. Mac 如何处理HOME目录以及在未设置实际目录的情况下检索实际HOME目录的方法。
  2. 如何正确使用命令行参数,因为cpLinux 上的 GNU 命令允许您以错误的方式进行操作,这导致了很多问题。
  3. 如何set -xv在脚本中用于调试。这将帮助您调试您遇到的大约 90% 的 shell 脚本错误。
  4. 我认为您的脚本实际上是错误的。不幸的是,由于缺乏信息,这是一个疯狂的猜测,但这是一个很好的猜测。

Mac 如何处理主目录

Mac OS X 是真正的 Unix 版本。事实上,它甚至比 Linux 更像 Unix。因此,它应该与几乎所有系统都相当兼容。

Mac 主目录存储在该/Users目录下。在 Mac 使用的默认 BASH shell 中(甚至在旧的 Turbo Csh 中),您可以将~其用作$HOME.

 $ echo "$HOME"   # Use quotes around directory and file names to avoid 
 $                # problems with white spaces.
 $ echo ~         # Echos the `$HOME` directory.

如果有人更改了HOME环境变量,您可以使用~userName来获取目录的正确HOME

$ echo $HOME
/Users/david
HOME=/tmp
$ echo $HOME
/tmp
$ echo ~
/tmp
$ echo ~david
 /Users/david
$ HOME=~david   #Fixed!

命令行参数

该错误可能与您计算机的Macness没有任何关系。这可能是您在几乎任何计算机上都能找到的标准问题。Mac 的cp命令采用-ror-R命令。与cpLinux 系统上的 GNU 不同,Mac 可以正确处理命令行参数。

例如,在 Linux 上,这是可以接受的:

$ cp "$dir" "$dir2" -r

在 Unix 系统上,这可能会失败。您需要-r命令后的参数:

$ cp -r "$dir" "$dir2"

如果您cp像第一个示例中那样执行命令,它将无法在 Unix 上运行,也无法在 Mac 上运行。

调试 Shell 脚本

现在,我们已经完成了一些初步准备,让我们看看如何调试您的问题......

放在set -xv第 14 行之前(可能在前面几行以确定)。这将打开脚本调试。该-x参数将在执行该行之前使用插值回显命令行。这样,您可以看到正在执行的实际命令。

该参数将按原样-v回显该行,无需插值。这样,您可以看到命令的外观,并可能检测到环境变量设置中的错误。

这是一个简单的脚本:

 name="David"
 echo "Hello $name!"

执行脚本,我们得到:

 $ test.sh
 Hello David!
 $

现在,我会这样做:

 set -xv
 name="David"
 echo "Hello $name!"
 set +xv     #Turns off the -xv flags

现在,我会得到这个:

 $ ./test.sh
 name="David"
 + name=David
 echo "Hello $name!"
 + echo 'Hello David!'
 Hello David!

另一个巧妙的技巧是设置PS4为“ ${LINENO}:”。这将在每一行前面加上行号,而不仅仅是+上面的 a:

可能的解决方案

我有一种感觉,问题在于您的目录名称中带有空格。引用目录和文件名以防止这些空格给您带来问题:

my_pictures=$HOME/"My Pictures"
cp -R $my_pictures $target     #Won't work due to the space between "My" & "Pictures"
cp -R "$my_pictures" "$target" #The quotes solve the problem.

结论

不用担心您的 Mac与众不同。它只是另一个 Unix 系统。确保您正确使用命令行参数,cp -R $dir1 $dir2而不是cp $dir $dir2 -R. 用于set -xv帮助您定位错误,并养成引用环境变量的习惯,因为环境变量值中的空格或制表符可能会导致程序失败。


Mac OS X 上的注意事项 - Lion

根据手册页,-r不再记录为选项。但是它确实有效。根据手册页:

cp 实用程序的历史版本有一个 -r 选项。此实现支持该选项;但是,强烈建议不要使用它,因为它不能正确复制特殊文件、符号链接或文件。

但是,cp -R应该可以在 Linux 上运行,并且在 Mac OS X 中作为递归复制标志记录。

于 2012-06-22T20:34:22.827 回答
1

$HOME 应该设置,但不能保证。用户可以覆盖此变量。另一种选择是使用getent.

IFS=: read -r _ _ _ _ _ homedir _ < <(getent passwd myuser)
echo "$homedir"
于 2012-06-22T18:20:38.737 回答
1

我不喜欢脚本中的 ~ 并且 $HOME 有时会失败,具体取决于您使用的外壳 - 也许不是在 OSX 上,但我不在乎..

不知何故,系统记录了用户的主目录在哪里,并且 $HOME 是从那里设置的。

具体来说,我通常试图找到另一个用户的主目录(同样不喜欢脚本中的〜缩写 - 称之为偏好)对于OSX,我使用这个 -

 finger $username | awk '/^Directory/ {print $2}'

在其他任何地方,我通常 grep /etc/passwd,但仔细想想,finger 可能会更通用。

这是我快速而肮脏的答案。如果您更好地了解 OSX 内部,将会有更好的解决方案 - 但关心因素?这对我有用

于 2016-04-23T04:38:33.693 回答