3

我正在尝试使用 bash 脚本自动化我与 git 的一些交互。为此,我有一个脚本,它将 ssh 并列出所有存储库,然后克隆它们。部分脚本显示在这里

DIRS=`ssh $u "ls $p"`;
for DIR in $DIRS; do
    echo "ssh://$u$p$DIR"
    echo "git clone ssh://$u$p$DIR";  
    git clone ssh://$u$p$DIR
done

示例参数是

-u user@host

-p /cygdrive/c/Documents\ and\ Settings/somePath

这适用于名称中包含空格的文件路径,直到 git clone 部分引发关于太多空格的错误。如果我复制并粘贴由

echo "git clone ssh://$u$p$DIR";

然后它克隆就好了。我试图用引号括起来,但它会引发错误

does not appear to be a git repository

我究竟做错了什么?

编辑 1

使用时的错误git clone "ssh://$u$p$DIR"

fatal: '/cygdrive/c/Documents\ and\ Settings/somePath/repo1' does not appear to be a git repository
fatal: The remote end hung up unexpectedly
4

5 回答 5

3

如果您的目录名称包含空格,您肯定不想这样做:

DIRS=`ssh $u "ls $p"`;
for DIR in $DIRS; do

由于您想保留空格而不是将它们用作分隔符,因此普遍接受的这样做方法是告诉 bash 分隔符是换行符:

IFS=$'\n'
for DIR in `ssh $u "ls -1 $p"`; do

如果你真的必须有你的变量DIRS,你可以使用 bash 的数组变量(这将保留你的空间):

IFS=$'\n'
DIRS=(`ssh $u "ls -1 $p"`)
unset IFS
for DIR in "${DIRS[@]}"; do

另一种通用形式是使用read

ssh $u "ls -1 $p" | while read DIR; do

或者:

while read DIR; do
    ...
done < <(ssh $u "ls -1 $p")

但是,不建议将这些作为错误处理(尤其是ssh当您开始使用管道时会涉及更多。)

到目前为止,一切都只是基本的 bash 脚本。

至于这一行,您需要用双引号将第二个参数括起来,因为其中的空格$DIR会产生第三个参数:

git clone "ssh://$u$p$DIR"

我在 git 中试过这个,它似乎工作。然而,正如@holygeek 所说,替换空格%20似乎也有效,并且在某些情况下可能有益。你可以这样做:

git clone "ssh://$u$p${DIR// /%20}"
于 2012-09-10T01:10:12.557 回答
1

您的问题几乎可以肯定是文件名中的空格

find并且xargs可以支持一种特殊模式,在这种模式下,它们使用\0(空)字符而不是空格来分隔文件名。

尝试这个:

ssh $u find $p -depth 0 -print0 | xargs -0 -J % git clone ssh://$u%

您可以通过运行轻松调试示例中的脚本

bash -x myscript.sh

然后它将在执行之前打印出每个命令行。那应该让您在问题出现之前找到它实际运行的内容。

于 2012-09-09T19:44:58.963 回答
1

你有两个问题。一个是你使用ls的,它对文件名做了各种奇怪的事情。不要解析ls. 另一个是你没有在$u$p$DIR. 始终在命令替换周围加上双引号(除非变量的值是由空格分隔的 glob 模式列表,这种情况很少见)。

请注意,通常,$p也需要引用。由于它正在通过 ssh,因此您无法避免它在另一端被解释。如果$p不包含任何 shell 特殊字符,例如空格,这并不太难。如果是这样,保护它们的最简单方法是$p在本地扩展,并在其周围加上单引号。单引号形成远程 shell 的字符串文字,除了 where$p包含单引号。这些需要替换为序列'\''。Bash 的${p//PATTERN/REPLACEMENT}构造解析规则有点奇怪;使用中间变量的两步过程$q完成了这项工作。

如果您可以依赖不包含任何换行符的文件名,则可以在远程端每行打印一个文件名。

q=\'\\\'\'
ssh "$u" "cd '${p//\'/$q}' && for x in *; do echo \"\$x\"; done" | {
  p=${p%/}
  p=${p//%/%3f}
  case $p in
    /*) :;;
    *) p="/~/$p";;
  esac
  while IFS= read -r DIR; do
    DIR=${DIR//%/%3f}
    git clone "ssh://$u$p/$DIR"
  done
}

请注意,$p$DIR将需要在 git ssh:URL 中进一步引用某些特殊字符。空格没问题,但%至少需要转义到%3f. 在上面的代码中,我添加了对它的支持,以及对何时$p是相对路径的情况的支持(将相对于主目录进行解释)。

于 2012-09-09T23:41:38.373 回答
0

我使用了GillesAntak 的回答中的信息来找到解决方案以及其他一些关于在远程机器上运行 ssh在 bash heredoc 中使用变量的帖子。

正如 Gilles 所建议的那样,我避免使用ls并且我已经使用 Antak 的建议IFS=$'\n' 来避免空格中的多个参数和换行符上的拆分参数。

我确定的最终代码是

DIRS=`ssh "$u" << ENDSSH
    cd "$p"
    eval 'for file in *; do echo \\$file; done'
ENDSSH`

IFS=$'\n'
for DIR in $DIRS;
    do
    echo "ssh://$u$p/$DIR"
done
unset IFS 
于 2012-09-10T16:41:32.853 回答
-2

看看用 %20 替换空格是否适合你。

于 2012-09-09T22:34:09.097 回答