将命令存储在变量中而不进行评估 - Unix

将命令存储在变量中而不进行评估 - Unix

我试图将命令存储在变量中,以便稍后可以在远程服务器上运行它。星号将替换为文件夹名称并存储在变量中。我需要该命令与星号一样,以便以后使用。

脚本:

#!/bin/bash
cmd="ls -lrt /client/*/ver* /client/*/*/ver*  | grep 299 | tail -1"
echo $cmd

输出:

./script.sh 
ls -lrt /client/folder299/version_1 /client/ifolder299/ifolder/version_a /client/ifolder300/ifolder1/version_b /client/ifolder301/ifolder2/version_c /client/ifolder302/ifolder3/version_d | grep 299 | tail -1

我尝试四处寻找但没有运气。有人可以帮我找到一种按原样存储命令的方法吗?

答案1

该命令不会被计算,字符串会按原样存储在变量中。当您输出未加引号的变量时,会扩展通配模式。


cmd="ls -lrt /client/*/ver* /client/*/*/ver*  | grep 299 | tail -1"

这是安全的,可以设置cmd为文字字符串ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1。在这种情况下,在字符串周围使用双引号和单引号之间的区别并不重要(但我会使用单引号,因为这是一个静态字符串)。从某种意义上说,shell 不需要在字符串中执行任何扩展,这并不重要。如果字符串中存在变量或命令替换,shell 会扩展它们,但实际上什么也没有。

当你输出使用变量的值echo $cmd,通配模式将被扩展(这就是发生的情况),但命令仍然不会运行。

要阻止扩展通配模式,请将变量扩展双引号为"$cmd"。就我个人而言,我会使用

printf '%s\n' "$cmd"

打印它的值。看 ”为什么 printf 比 echo 更好?”为什么。

有关的:


另请注意,由于您正在解析ls -l( 其本身不安全),然后查找一个数字,您可以从任何地方ls -l输出中,例如文件的大小。

我建议您重新思考您要解决的更大问题是什么,然后提出一个全新的问题反而。

要从路径名列表中查找最近修改的常规文件,您可以这样做

unset newest
for pathname in /client/*/ver* /client/*/*/ver*; do
    if [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
        newest=$pathname
    fi
done

这是假设您提到的文件名通配模式扩展到您想要检查的名称。另外将其限制为仅允许包含字符串的文件名299

unset newest
for pathname in /client/*/ver* /client/*/*/ver*; do
    if [[ "${pathname##*/}" == *299* ]] &&
        [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
        newest=$pathname
    fi
done

如果通配模式扩展到您需要递归查看的目录,则使用bash

shopt -s globstar
unset newest
for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "${pathname##*/}" == *299* ]] &&
        [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
        newest=$pathname
    fi
done

通过 SSH 运行此示例:

ssh user@host bash -s -O globstar <<'END_SCRIPT'
for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "${pathname##*/}" == *299* ]] &&
        [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
        newest=$pathname
    fi
done
printf 'Newest file: %s\n' "$newest"
END_SCRIPT

答案2

可能是选项 f :

$ touch /tmp/filetmp
$ c="ls /tmp/*"

$ set -f
$ echo $c
ls /tmp/*

$ set  +f
$ echo $c
ls /tmp/filetmp

$ rm /tmp/filetmp
$ unset c

在linux下,通常默认选项是+f

答案3

对于上述的混乱,我们深表歉意。

通过按以下方式直接提供命令即可解决该问题。

ssh username@host "ls -lrt /client/*/ver* /client/*/*/ver* | grep $4 | tail -1" 

答案4

将命令存储到变量中时使用单引号。在echo命令中使用时使用双引号。

$ cmd='ls -lrt /var/* /tmp/* /home/* | grep test | tail -1'
$ echo "$cmd"
ls -lrt /var/* /tmp/* /home/* | grep test | tail -1

单引号和双引号的区别

相关内容