简体   繁体   English

以bash转义引号(Embedded awk)

[英]Escaping quotes in bash (Embedded awk)

I have a complex command I am passing via ssh to a remote server. 我有一个复杂的命令,我要通过ssh传递给远程服务器。 I am trying to unzip a file and then change its naming structure and extension in a second ssh command. 我试图解压缩文件,然后在第二个ssh命令中更改其命名结构和扩展名。 The command I have is: 我有的命令是:

ssh root@server1 "gzip -d /tmp/file.out-20171119.gz; echo file* | awk -F'[.-]' '{print $1$3".log"}'"

Obviously the " around the .log portion of the print statement are failing me. The idea is that I would strip the .out portion from the filename and end up with file20171119.log as an ending result. I am just a bit confused on the syntax or on how to escape that properly so bash interprets the .log appropriately. 显然,print语句的.log部分周围的“令我失败。我的想法是,我将从文件名中删除.out部分,最后得到file20171119.log作为结束结果。语法或有关如何正确进行转义的内容,因此bash会正确解释.log。

The easiest way to deal with this problem is to avoid it. 解决此问题的最简单方法是避免它。 Don't bother trying to escape your script to go on a command line: Pass it on stdin instead. 不要费心尝试转义脚本以进入命令行:而是在stdin上传递它。

ssh root@server1 bash -s <<'EOF'
  gzip -d /tmp/file.out-20171119.gz
  # note that (particularly w/o a cd /tmp) this doesn't do anything at all related to the
  # line above; thus, probably buggy as given in the original question.
  echo file* | awk -F'[.-]' '{print $1$3".log"}'
EOF

A quoted heredoc -- one with <<'EOF' or <<\\EOF instead of <<EOF -- is passed literally, without any shell expansions; 一个带引号的heredoc-用<<'EOF'<<\\EOF代替<<EOF -按<<EOF传递,没有任何shell扩展; thus, $1 or $3 will not be replaced by the calling shell as they would with an unquoted heredoc. 因此, $1$3将不会被调用shell替换,就像用未引用的heredoc那样。


If you don't want to go the avoidance route, you can have the shell do the quoting for you itself. 如果您不想走回避路线,则可以让Shell自己为自己报价。 For example: 例如:

external_function() {
  gzip -d /tmp/file.out-20171119.gz
  echo file* | awk -F'[.-]' '{print $1$3".log"}'
}

ssh root@server1 "$(declare -f external_function); external_function"

declare -f prints a definition of a function. declare -f打印函数的定义。 Putting that function literally into your SSH command ensures that it's run remotely. 从字面上将功能放入SSH命令可确保它可以远程运行。

您需要转义"以防止它们提早关闭带引号的字符串,并且需要转义awk脚本中的$以防止局部参数扩展。

ssh root@server1 "gzip -d /tmp/file.out-20171119.gz; echo file* | awk -F'[.-]' '{print \$1\$3\".log\"}'"

The most probable reason (as you don't show the contents of the root home directory in the server) is that you are uncompressing the file in the /tmp directory, but feeding to awk filenames that should exist in the root home directory. 最可能的原因(因为您未在服务器中显示root主目录的内容)是您要解压缩/tmp目录中的文件,但要提供到root主目录中应存在的awk文件名。

" allows escaping sequences with \\ . so the correct way to do is "允许用\\转义序列,因此正确的做法是

ssh root@server1 "gzip -d /tmp/file.out-20171119.gz; echo file* | awk -F'[.-]' '{print \$1\$3\".log\"}'"

(like you wrote in your question) this means the following command is executed with a shell in the server machine. (就像您在问题中所写的一样),这意味着以下命令是使用服务器计算机中的外壳执行的。

gzip -d /tmp/file.out-20171119.gz; echo file* | awk - F'[.-]' '{print $1$3".log"}'

You are executing two commands, the first to gunzip /tmp/file.out-2017119.gz (beware, as it will be gunzipped in /tmp ). 您正在执行两个命令,第一个命令对/tmp/file.out-2017119.gz进行gunzip(请注意, 因为它将被压缩/tmp )。 And the second can be the source for the problem. 第二个可能是问题的根源。 It is echoing all the files in the local directory (this is, the root user home directory, probably /root in the server) that begin with file in the name (probably none), and feeding that to the next awk command. 它回显本地目录 (这是root用户主目录,可能是服务器中的/root )中所有以名称(可能没有)开头的file ,并将其提供给下一个awk命令。

As a general rule.... test your command locally, and when it works locally, just escape all special characters that will go unescaped, after being parsed by the first shell. 作为一般规则...。在本地测试您的命令,当它在本地工作时,只需在第一个shell解析后转义所有将转义的特殊字符即可。

another way to solve the problem is to use gzip(1) as a filter... so you can decide the name of the output file 解决该问题的另一种方法是使用gzip(1)作为过滤器...因此您可以确定输出文件的名称

ssh root@server1 "gzip -d </tmp/file.out-20171119.gz >file20171119.log"

this way you save an awk(1) execution just to format the output file. 这样,您保存awk(1)执行只是为了格式化输出文件。 Or if you have the date from an environment variable. 或者,如果您有来自环境变量的日期。

DATE=`date +%Y%m%d`
ssh root@server1 "gzip -d </tmp/file.out-${DATE}.gz >file${DATE}.log"

Finally, let me give some advice: Don't use /tmp to uncompress files. 最后,让我给出一些建议:不要使用/tmp解压缩文件。 /tmp is used by several distributions as a high speed temporary dir. /tmp被多个发行版用作高速临时目录。 It is normally ram based, too quick, but limited space, so uncompressing a log file there can fill up the memory of the kernel used for the ram based filesystem, which is not a good idea. 它通常是基于ram的,速度太快,但是空间有限,因此解压缩日志文件可能会填满用于基于ram的文件系统的内核内存,这不是一个好主意。 Also, a log file normally expands a lot and /tmp is a local system general directory, where other users can store files named file<something> and you can clash with those files (in case you do searches with wildcard patterns, like you do in your command) Also, it is common once you know the name of the file to assign it to environment variables and use those variables, so case you need to change the format of the filename, you do it in only one place. 另外,日志文件通常会扩展很多, /tmp是本地系统常规目录,其他用户可以在其中存储名为file<something>并且您可以与这些文件冲突(以防万一,例如使用通配符模式进行搜索同样在您知道将文件分配给环境变量并使用这些变量的文件名后,这很常见,因此,如果您需要更改文件名的格式,则只需在一个地方进行即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM