it-swarm.cn

如何将命令的输出分配给Shell变量?

我想将表达式的结果分配给变量并将其与字符串连接,然后回显它。这是我得到的:

#!/bin/bash
cd ~/Desktop;
thefile= ls -t -U | grep -m 1 "Screen Shot";
echo "Most recent screenshot is: "$thefile;

但是输出:

Screen Shot 2011-07-03 at 1.55.43 PM.png
Most recent screenshot is: 

因此,似乎没有分配给$thefile,并在执行时被打印。

82
Nathan G.

Shell分配是一个单词,等号后没有空格。因此,您编写的内容为thefile分配了一个空值;此外,由于赋值与命令分组在一起,因此它使thefile成为环境变量,并且该赋值对于该特定命令而言是本地的,即,仅对ls的调用才能看到赋值。

您要捕获命令的输出,因此需要使用 命令替换

_thefile=$(ls -t -U | grep -m 1 "Screen Shot")
_

(某些文献显示了_thefile=`ls …`_的另一种语法;反引号语法与美元括号语法等效,只是有时反引号内的引用很奇怪,因此只需使用$(…)。)

有关脚本的其他说明:

  • 将_-t_(按时间排序)与_-U_(不排序)组合起来是没有意义的;只需使用_-t_。
  • 与其使用grep来匹配屏幕截图,不如将通配符传递给ls并使用head来捕获第一个文件更加清晰:

    _thefile=$(ls -t *"Screen Shot"* | head -n 1)
    _
  • 通常是 解析ls的输出的坏主意 。如果文件名带有不可打印的字符,则可能会严重失败。但是,如果没有ls,则很难按日期对文件进行排序,因此,如果您知道文件名中没有不可打印的字符或反斜杠,那么这是一个可以接受的解决方案。

  • 总是在变量替换处使用双引号,即在这里写

    _echo "Most recent screenshot is: $thefile"
    _

    如果没有双引号,则变量的值会重新扩展,如果它包含空格或其他特殊字符,则会引起麻烦。

  • 您不需要在行尾使用分号。它们是多余的但无害。
  • 在Shell脚本中,包含 _set -e_ 通常是一个好主意。这告诉命令行管理程序如果任何命令失败(通过返回非零状态)则退出。

如果您有GNU)查找(特别是如果您正在运行非嵌入式Linux或Cygwin),则还有另一种查找最新文件的方法:find列出文件及其日期,并使用sorttail提取最年轻的文件。

_thefile=$(find -maxdepth 1 -type f -name "*Screen Shot*" -printf "%[email protected] %p" |
          sort -k 1n | tail -n 1)
_

如果您愿意用zsh而不是bash编写此脚本,则有一种捕获最新文件的简便方法,因为zsh具有 glob qualifiers ,它不仅允许名称上的通配符匹配,而且还允许文件上的通配符匹配元数据。模式之后的_(om[1])_部分是全局限定符; om会根据年龄的增长来对匹配项进行排序(即,按照修改时间,最新的优先),而_[1]_仅提取第一个匹配项。整个匹配项都需要放在括号中,因为从技术上讲它是一个数组,因为遍历会返回文件列表,即使_[1]_意味着在这种特殊情况下,列表最多包含一个文件。

_#!/bin/zsh
set -e
cd ~/Desktop
thefile=(*"Screen Shot"*(om[1]))
echo "Most recent screenshot is: $thefile"
_
114

如果要使用多行/多命令执行此操作,则可以执行以下操作:

output=$( bash <<EOF
#multiline/multiple command/s
EOF
)

要么:

output=$(
#multiline/multiple command/s
)

例:

#!/bin/bash
output="$( bash <<EOF
echo first
echo second
echo third
EOF
)"
echo "$output"

输出:

first
second
third
4
Jahid