【问题标题】:Unix shells: How to ensure command works against most common shells?Unix shell:如何确保命令适用于最常见的 shell?
【发布时间】:2021-01-30 13:01:09
【问题描述】:

我有一些使用 jsch 连接到我们的 unix 服务器并在命令下运行的 java 代码。

ls -lt /tempdirectory/ grep -v '^do | grep "$"(日期 '+%b %e')" | 头 -1 | awk '{print %9}'

上面的命令以长格式显示 /temp 目录中的所有文件(第一个管道删除目录)。然后从结果中筛选出今天创建的所有文件(即它 greps 为“Oct 16”)。因为我做了 ls -lt 文件是按时间排序的,所以当我对 head -1 进行管道时,我今天会得到最新的文件。然后最后一个管道会打印出文件名

在普通的 putty 终端上,一旦我切换到 bash shell 并运行上面的命令,它将正确打印出今天的最新文件。

但默认 shell 似乎是 Bourne (-sh),上面的命令会失败(因此我的代码会失败)

有没有一种方法可以创建对普通 shell 安全的上述命令?我认为我在工作中看到的主要 shell 是:

伯恩 (sh) 再次伯恩(bash) 科恩 (ksh)

【问题讨论】:

  • 请注意,在现代系统上,sh 不是 Bourne 而是 POSIX sh。这个 1992 年的标准(与 1970 年代的 Bourne 相比)要求包含 $(...)。我强烈反对任何关于 POSIX 之前的 Bourne 在 2020 年“普遍”的说法。
  • 我所知道的在过去 20 年中交付真正 Bourne 的唯一操作系统供应商是 Sun。绝对其他人都在使用真正的 POSIX sh
  • 啊我的操作系统是sunOS哈哈
  • 系统上也可能有 POSIX sh。我想说/usr/xpg/bin/sh 之类的东西。

标签: java bash shell unix


【解决方案1】:

根据 cmets,我发现了问题。 Bourne 无法处理 $(...) 因此我需要将其替换为 --> `

参考: https://www.unix.com/shell-programming-and-scripting/188983-syntax-error-line-24-unexpected.html

所以命令变成了

ls -lt /临时目录/ | grep -v '^d' | grep "date '+%b %e'" |头-1 | awk '{打印 $9}'

我不知道这是否适用于许多不同的 shell,但它似乎适用于 sh 和 bash

由于某种原因,StackOverflow 没有正确显示该撇号,所以我将澄清我在第一个双引号之后和最后一个双引号之前添加了奇怪的另一个撇号:

"{这里}日期'+%b %e'{这里}"

(也基于以前的 cmets,听起来这不仅仅是您在确定命令兼容性时使用的 shell 的问题 - 您的底层操作系统也可能会产生影响。在我的情况下,使用 uname -a 表明我是使用 sunOS)

【讨论】:

    【解决方案2】:

    您发布的代码

    ls -lt / grep -v '^do | grep "$"(date '+%b %e')" | head -1 |awk'{print %9}'

    有语法错误,不能在任何shell中运行

    把它改成

     ls -lt  /tempdirectory/ | grep -v '^d' | grep "$(date '+%b %e')" | head -1 | awk '{print $9}'
    

    它与 ANSI 兼容,可在 shbashzsh 中运行(我已经测试过)。

    【讨论】:

    • 您好,很抱歉我在手机上输入的语法错误。问题是当我在 sh 中运行命令时它什么也不返回(而在 bash 中它确实返回今天的文件)。据我了解,问题似乎来自 grep date 命令。即使我将您的答案直接复制粘贴到控制台中,它也不起作用
    • 如果我输入: echo $(date '+%b %e') in sh 我得到语法错误:'(' 意外。而如果我在 bash 中运行它,它将按预期输出日期.
    • 我搜索了错误并发现 Bourne (sh) 无法处理 $() 因此我将其替换为 ``(那个奇怪的其他撇号)。有了这个,整个命令现在似乎可以在 sh 和 bash 中运行。虽然有趣的是,现在我的 jsch exec 程序因 ArrayIndexOutOfBoundsException 出错:Index 1 out of bounds for length 1
    • 发现我的 java 错误由于其他原因而不是由于我的命令而失败。现在一切似乎都正常了!感谢您的帮助
    • 请始终从命令行复制粘贴代码,不要重新输入。
    【解决方案3】:

    这是您应该使用find(1) 命令的地方:

    $ find /tmpdir -type f -ctime -1 
    

    /tmpdir 获取今天创建(ctime)的所有文件。

    如果你想要所有的文件,那么你就不需要更多的修饰符了。如果您想进一步限制,请参阅https://linux.die.net/man/1/find 的 GNU Find 手册页。

    find(1) 命令与您可以访问远程计算机上的哪个 shell 无关。

    【讨论】:

    • 重要的是文件是从今天午夜开始创建的。我创建了测试文件并使用 (touch -a -m -t 202010152359.59 test1.txt) 修改了它们的日期,并创建了边缘案例,例如在晚上 11:59 和午夜之后创建的文件以及昨天凌晨 1 点创建的文件。看来您的命令只是找到所有文件。我也尝试用 mtime 替换 ctime,但我可以看到它打印除了昨天凌晨 1 点制作的文件之外的所有文件(即,它看起来像是找到过去 24 小时的所有文件,而不是今天午夜的所有文件)
    • 我尝试在您的链接中使用该 daystart 参数,但是当我在 bash 和 bourne 中尝试时,它似乎给出了错误的参数选项错误?
    • 如果您有一个带有适当时间戳的参考文件,您可以使用-cnewer /path/to/reference/file 来获取在该文件之后创建的所有内容。对于 mtime(修改)和 atime(访问)也是如此
    • 很遗憾我没有参考文件
    • 你可以用touch创建一个:touch -t "$(date +"%Y%m%d0000")" ref_file
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    • 2011-12-11
    • 1970-01-01
    • 2011-08-03
    • 2015-02-24
    • 2018-05-08
    • 1970-01-01
    相关资源
    最近更新 更多