转义shell cmd行嵌套引号

时间:2018-02-28 01:33:11

标签: shell sh

我有很多正在运行的后台作业正在提供各自的日志文件。使用watch命令我正在监视日志中的相应最后一行,如下所示。

watch "ls -rtdc1 base_*.log | tail -20 | xargs -I % sh -c 'tail -vn1 % | cut -c1-180'"

看起来很不错,但它的文件名来自tail -v,并且日志后面有一行换行符。我想两者保持一致。下面的小awk cmd将只组合两行,它可以单独测试。

awk 'NR%2{printf "%s ",$0;next;}1'

好的,现在结合这两个是挑战。很多单引号和双引号值得注意。我尝试了以下一行失败了。

watch "ls -rtdc1 base_*.log | tail -20 | xargs -I % sh -c 'tail -vn1 % | awk \'NR%2{printf "%s ",$0;next;}1\' | cut -c1-180'"

所以我的问题是为cmd线找到正确的转义序列。

非常感谢您的反馈。

2 个答案:

答案 0 :(得分:1)

正确的做法是以这样一种方式构建代码,使您根本不需要引用代码来使其按字面意思处理

请考虑以下内容(注意到我的函数定义在此处占位符的任何地方,它应该替换为给定的myfn定义,或者等效于其中的东西):

#!/usr/bin/env bash
#              ^^^^-- needed for exported functions

myfn() {
  # aside: parsing ls is a Really Bad Idea; don't do this.
  # See https://mywiki.wooledge.org/ParsingLs for discussion of why not.
  # See https://mywiki.wooledge.org/BashFAQ/003 for alternate practices.
  ls -rtdc1 base_*.log \
  | tail -20 \
  | while read -r line; do
      tail -v1 "$line" \
      | awk 'NR%2 {printf "%s ",$0; next; }1' \
      | cut -c1-180
    done
}
export -f myfn
watch 'bash -c myfn'

或者,没有export -f(并且要求bash仅作为外壳,而不是内壳):

#!/usr/bin/env bash
#              ^^^^- needed for declare -f

myfn() { echo "Function definition goes here"; }

watch "$(declare -f myfn); myfn"

或者,只需要 / bin / sh:

#!/bin/sh

cat_myfn() {
  cat <<'EOF'
myfn() { echo "Function definition goes here"; }
EOF
}

watch "$(cat_myfn)
myfn"

答案 1 :(得分:1)

查尔斯对你的具体问题有一个很好的答案。如果你问的是引用的一般问题,那么GNU Parallel可以为你做到这一点:

$ parallel --shellquote
NR%2{printf "%s ",$0;next;}1
[Ctrl-D]

所以awk NR%2\{printf\ \"%s\ \",\$0\;next\;\}1应该有用。接下来引用sh -c的命令:

$ parallel --shellquote
tail -vn1 % | awk NR%2\{printf\ \"%s\ \",\$0\;next\;\}1 | cut -c1-180
[Ctrl-D]

,并提供:

tail\ -vn1\ %\ \|\ awk\ NR%2\\\{printf\\\ \\\"%s\\\ \\\",\\\$0\\\;next\\\;\\\}1\ \|\ cut\ -c1-180

但是,由于您在awk命令中使用%,因此需要为xargs使用另一个替换字符串。我们使用{}:

ls -rtdc1 base_*.log | tail -20 | xargs -I {} sh -c tail\ -vn1\ {}\ \|\ awk\ NR%2\\\{printf\\\ \\\"%s\\\ \\\",\\\$0\\\;next\\\;\\\}1\ \|\ cut\ -c1-180

最后引用watch

$ parallel --shellquote
ls -rtdc1 base_*.log | tail -20 | xargs -I {} sh -c tail\ -vn1\ {}\ \|\ awk\ NR%2\\\{printf\\\ \\\"%s\\\ \\\",\\\$0\\\;next\\\;\\\}1\ \|\ cut\ -c1-180
[Ctrl-D]

,并提供:

ls\ -rtdc1\ base_\*.log\ \|\ tail\ -20\ \|\ xargs\ -I\ \{\}\ sh\ -c\ tail\\\ -vn1\\\ \{\}\\\ \\\|\\\ awk\\\ NR%2\\\\\\\{printf\\\\\\\ \\\\\\\"%s\\\\\\\ \\\\\\\",\\\\\\\$0\\\\\\\;next\\\\\\\;\\\\\\\}1\\\ \\\|\\\ cut\\\ -c1-180

因此应该有效:

watch ls\ -rtdc1\ base_\*.log\ \|\ tail\ -20\ \|\ xargs\ -I\ \{\}\ sh\ -c\ tail\\\ -vn1\\\ \{\}\\\ \\\|\\\ awk\\\ NR%2\\\\\\\{printf\\\\\\\ \\\\\\\"%s\\\\\\\ \\\\\\\",\\\\\\\$0\\\\\\\;next\\\\\\\;\\\\\\\}1\\\ \\\|\\\ cut\\\ -c1-180

你会用手写这种方式吗?可能不是。但是整个想法是让计算机为你工作 - 而不是相反。