反引号内的引号 ksh 中的引号内

Use*_*123 5 ksh hp-ux quoting timestamps

我正在尝试在 HP-UX Unix 中使用以下命令获取当前日期的文件:

$ ls -lrt ABC.LOG* |grep "`date +"%b %d"`"
Run Code Online (Sandbox Code Playgroud)

但是,它给了我错误:

ksh: : cannot execute
grep: can't open %d
Run Code Online (Sandbox Code Playgroud)

有什么建议?

Kus*_*nda 7

该错误源于对 的参数的引用grep以及反引号不能很好地嵌套的事实:

grep "`date +"%b %d"`"
Run Code Online (Sandbox Code Playgroud)

这最好写成

grep "`date +'%b %d'`"
Run Code Online (Sandbox Code Playgroud)

……甚至更好,

grep "$(date +'%b %d')"
Run Code Online (Sandbox Code Playgroud)

事实上,使用$(...)而不是反引号,您应该能够保留内部双引号:

grep "$(date +"%b %d")"
Run Code Online (Sandbox Code Playgroud)

grepping 输出的另一种方法ls是做

find . -type f -name "ABC.LOG*" -ctime -1
Run Code Online (Sandbox Code Playgroud)

这将-type f在当前目录中查找名称与给定模式匹配且 ctime自当前时间起小于 24 小时的所有常规文件 ( ) 。文件的 ctime 是最后一次修改文件数据或元数据的时间。

但这并不完全等同于您想要实现的目标。这也会递归到子目录中。


Sté*_*las 5

在 Korn shell 中,就像在 Bourne shell 中一样,引号和反引号(命令替换的古老形式)可能是无与伦比的,您必须帮助标记生成器分辨反引号在哪里结束。在反斜杠内部还有另一个级别的反斜杠处理。

echo "`date"
Run Code Online (Sandbox Code Playgroud)

有效并且与以下相同:

echo "`date`"
echo "$(date)"
Run Code Online (Sandbox Code Playgroud)

和:

echo `echo "foo`
Run Code Online (Sandbox Code Playgroud)

有效并且与以下相同:

echo `echo "foo"`
echo $(echo "foo")
Run Code Online (Sandbox Code Playgroud)

如果你这样做:

grep "`date +"%b %d"`"
Run Code Online (Sandbox Code Playgroud)

这作为一个的grep单词,然后"`date +"(双引号内未关闭反引号)串联起来%b,然后%d用双引号内的另一个未闭合的反引号连接起来:"`"。所以就像

grep "$(date +)"%b %d"$()"
Run Code Online (Sandbox Code Playgroud)

(除了出于某种原因,虽然echo "``"echo "$()"不会导致错误,在 中echo "`",shell 将尝试执行具有空名称的命令(就像您编写的一样echo "$("")")。

所以在这里,你需要使用反斜杠来帮助解析器:

grep "`date +\"%b %d\"`"
Run Code Online (Sandbox Code Playgroud)

这些反斜杠实际上已被删除。它是date +"%b %d"由命令替换中的子shell 评估的。

在这里,由于ksh接受未封闭的引号,您实际上也可以这样做:

grep "`date +\"%b %d"
Run Code Online (Sandbox Code Playgroud)

(不是我会建议这样做)。

这也是您如何获得嵌套反引号的方法,如下所示:

echo "`echo \"\`echo \\\"a  b\\\"\`\"`"
Run Code Online (Sandbox Code Playgroud)

一个很好的例子,为什么几乎没有人使用这种语法并使用$(...)较新的形式(ksh在 80 年代初引入):

echo "$(echo "$(echo "a  b")")"
Run Code Online (Sandbox Code Playgroud)

现在,对于您的特定问题,您似乎想要列出ABC.LOG*当前目录中今天最后修改的文件。为此,你可以这样做:

touch -t "$(date +%Y%m%d0000)" .start-of-day &&
  find . ! -name . -prune -name 'ABC.LOG.*' \
    -newer .start-of-day -type f -exec ls -lrtd {} + &&
  rm -f .start-of-day
Run Code Online (Sandbox Code Playgroud)