转义shell cmd行嵌套引号

问题描述 投票:2回答:2

我有很多后台作业在运行它们各自的日志文件。使用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线的正确转义序列。

非常感谢您的反馈。

shell sh
2个回答
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
投票

查尔斯对你的具体问题有一个很好的答案。如果你问的是引用的一般问题,那么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

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

© www.soinside.com 2019 - 2024. All rights reserved.