我试图将命令存储在变量中,以便稍后可以在远程服务器上运行它。星号将替换为文件夹名称并存储在变量中。我需要该命令与星号一样,以便以后使用。
脚本:
#!/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