Bash脚本:保持本地文件的一行与远程文件同步

3

我已经寻遍天涯海角,但似乎找不到解决这个问题的方法(也许不存在?)。这就是我的问题:

我本地机器上有一个名为 myFile.txt 的文件。远程机器上也有一个同名文件(myFile.txt)。两个文件结构都是这样的:

<tag1>November 22, 2012<tag1>
<tag2>version5.8<tag2>
<tag3>ASDFA23RASDF29ASDJ29DJ2<tag3>

两个文件拥有完全相同的布局。我需要编写一个脚本来保持两个文件(本地和远程)<tag3>之间的字符串同步。我需要从远程服务器获取<tag3>中的字符串,并将其与本地机器上的相同字符串进行比较。如果存在差异,我需要更改本地字符串以反映远程字符串。
到目前为止,我的尝试: 我使用awk抓取了本地字符串,并将其分配给变量。很容易。我通过ssh登录到远程服务器,并尝试使用相同的方法将远程字符串分配给变量。据我所知,这似乎是有效的。问题是该变量没有带回本地机器的值(如果这有意义的话)。这是我尝试这样做的方式:
#!/bin/bash

fileName="myFile.txt"
logon="myUserName@remoteServer.com"


localString=$(awk -F "<tag3>" '{print $2}' $fileName)

x=$(ssh $logon "remoteString=$(awk -F "<tag3>" '{print $2}' $fileName); echo $remoteString")
echo "remote string = $x" 

if [ $localString == $x ]; then
echo "The 2 auth keys are EQUAL!!!"
else
echo "The 2 auth keys are NOT equal!!!"
fi  

我可以看到在echo $remoteString时变量被赋值,根据我的理解,这是在远程服务器上发生的,因为我正确地将字符串打印到控制台后跟着"command not found"。下一行输出"remote string = "。所以$x要么失去了它的值,要么从未得到正确的赋值。我已经尝试过多次变化$x被赋值的那一行,但都没有成功。
其他想法: 如果这不可能实现,我开始认为也许我需要通过scp命令将文件复制到我的服务器上,进行比较,然后删除复制的文件。在将其移动到我的本地机器之前,需要更改副本的名称,否则我将覆盖我的文件。此外,似乎更有效率的方法是不必创建一个安全的拷贝,因为此脚本将在许多机器上运行,且该文件的大小可能会很大,超过3行。我已经研究了diff命令,但无法找到一种只比较单行的方法。
我对bash编程相对较新,如果我漏掉了明显的东西,请谅解。感谢您的任何帮助,十分感激。
3个回答

1

ssh命令存在转义问题 - 应该在ssh参数中转义$

然后,我只是用awk ....替换了remoteString=$(awk ....); echo $remoteString。如果不这样做,就会出现一个前导空行的问题,导致字符串不匹配 - 存储命令输出只是为了将其echo似乎毫无意义。

#!/bin/bash

fileName="myFile.txt"
logon="myUserName@remoteServer.com"


localString=$(awk -F "<tag3>" '{print $2}' $fileName)

x=$(ssh $logon "awk -F '<tag3>' '{print \$2}' $fileName")
echo "remote string = $x" 

if [ "$localString" == "$x" ]; then
        echo "The 2 auth keys are EQUAL!!!"
else
        echo "The 2 auth keys are NOT equal!!!"
fi

这个有趣的结果。$x回显一个值,但它的值等于整个文件。也许我需要改变我的awk表达式?但是在本地它运行得很好? - nycfdtd
@nycfdtd 我觉得我没有理解你的评论。我发布的脚本和我在这里测试的脚本之间唯一的区别是 fileNamelogon。我正在对 localhost 运行它,所以两个 awk 都是使用相同的文件执行的。文件内容是你在问题中发布的那3行。我不知道你的系统是否有任何差异。可能会有什么问题吗? - mgarciaisaia
不确定 desert69。由于某种原因,当在远程服务器上运行相同的 awk 表达式时,它将整个文件内容分配给了 $x。因此,在回显 $x 的值时,整个文件都被打印出来。奇怪的是:在本地机器上使用完全相同的 awk 表达式,只提取 <tag3> 之间的值。 - nycfdtd
@nycfdtd 尝试使用 ssh 连接到 localhost。如果可以连接成功,那么问题可能出在远程文件、awk 或者是 shell 上?看起来很奇怪... - mgarciaisaia

1
您可以使用类似以下的内容:
#!/bin/bash 
fileName="myFile.txt"
logon="myUserName@remoteServer.com"

sedcommand='/^<tag3>.*<tag3>$/{s/<tag3>\(.*\)<tag3>/\1/p;q}'

localString=$( sed -n $sedcommand "$fileName" )
remoteString=$( ssh "$logon" "sed -n '$sedcommand' \"$fileName\"" )

if [[ $localString == $remoteString ]]; then
    echo "The 2 auth keys are EQUAL!!!"
else
    echo "The 2 auth keys are NOT equal!!!"
fi

(这似乎比您的方法更简单)。sed命令查找以<tag3>开头并以<tag3>结尾的行的第一个出现,并删除标记,以便仅传输“auth key”。没有防止不存在文件或标记未被找到的保护。这个细节留给读者。但是脚本在文件名中使用空格时是安全的,并且不使用两个嵌套的子shell!


这样就可以了!非常感谢。当我第一次开始做这个时,我尝试使用sed,但无法正确提取我的字符串。然后我转向awk,我很快就能够理解它。我需要更多地使用正则表达式。我认为这是sed遇到的障碍。 - nycfdtd

0

尝试更改这一行:

x=$(ssh $logon "remoteString=$(awk -F "<tag3>" '{print $2}' $fileName); echo $remoteString")

x=$(ssh $logon "remoteString=$(awk -F '<tag3>' '{print $2}' $fileName); echo $remoteString")

例如:将"<tag3>"更改为'<tag3>'

我有一种感觉,你当前使用的双引号实际上破坏了ssh命令的预期用途。


作为一个附注:当你在条件测试中使用单个[时,始终将变量用双引号括起来:
if [ $localString == $x ]; then

标签会更安全:

if [ "$localString" == "$x" ]; then

或者

# this also works, but less portable
if [[ $localString == $x ]]; then

原因是,如果任一变量的值为 null 字符串(假设在这种情况下 x 是空的),则 bash 会看到如下内容: if [ ASDFA23RASDF29ASDJ29DJ2 == ]; then

谢谢您的建议,但我仍然遇到相同的问题。在您引用的那一行,字符串被正确地回显出来,但是当我在下一行尝试回显$x时,变量就失去了其值。 - nycfdtd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接