Linux 如何在shell脚本变量中使用{old,new}名称?

Linux 如何在shell脚本变量中使用{old,new}名称?,linux,bash,shell,Linux,Bash,Shell,首先,您可以用linux shell进行的这些转换的名称是什么 $ echo {old,new}name oldname newname 我试着把它放在一个变量上,如下所示: $ var={old,new}name $ echo $var {old,new}name 但正如我们所看到的,它们停止了工作。我需要在变量上使用它们,以便在批量操作中轻松更改它们,如下所示: mv {old,new}name/"file 1.txt" mv {old,new}name/"file 2.txt" mv

首先,您可以用linux shell进行的这些转换的名称是什么

$ echo {old,new}name
oldname newname

我试着把它放在一个变量上,如下所示:

$ var={old,new}name
$ echo $var
{old,new}name
但正如我们所看到的,它们停止了工作。我需要在变量上使用它们,以便在批量操作中轻松更改它们,如下所示:

mv {old,new}name/"file 1.txt"
mv {old,new}name/"file 2.txt"
mv {old,new}name/"file 3.txt"
mv {old,new}name/"file 4.txt"
所以我可以这样写:

var={old,new}

mv '$var'name/"file 1.txt"
mv '$var'name/"file 2.txt"
mv '$var'name/"file 3.txt"
mv '$var'name/"file 4.txt"

此外,我在组合shell变量和
name
补码时遇到了困难,即
$varname
。我想在
$var
名称周围使用单引号,即
'$var'name
。想一想,这是最好的方法吗?

您可以将扩展结果存储在一个数组中:

var=( {old,new}name )      # performs expansion, stores results in var
printf '%s\n' "${var[@]}"  # prints "oldname" and "newname"
但是,大括号展开是在参数展开(即替换变量的值)之后进行的。这是出于令人信服的原因:如果数据被解析为代码,那么就不可能在bash中编写处理不受信任数据的脚本


坦白地说,对于您的示例代码,只需这样编写就可以缩短:

for name in name/"file "{1,2,3,4}.txt; do
  mv -- old"$name" new"$name"
done

这就是说,如果你想在没有极度谨慎的情况下做危险、不安全的事情,那么谨慎的方法可能看起来是这样的:

var='{old,new}'
for f in "file 1.txt" "file 2.txt" "file 3.txt" "file 4.txt"; do
  printf -v cmd 'mv %sname/%q' "$var" "$name" && eval "$cmd"
done

在这里,我们使用
%s
替换大括号扩展(手写的、受信任的代码),并使用
%q
替换(可能不受信任的)文件名。

您可以将扩展结果存储在数组中:

var=( {old,new}name )      # performs expansion, stores results in var
printf '%s\n' "${var[@]}"  # prints "oldname" and "newname"
但是,大括号展开是在参数展开(即替换变量的值)之后进行的。这是出于令人信服的原因:如果数据被解析为代码,那么就不可能在bash中编写处理不受信任数据的脚本


坦白地说,对于您的示例代码,只需这样编写就可以缩短:

for name in name/"file "{1,2,3,4}.txt; do
  mv -- old"$name" new"$name"
done

这就是说,如果你想在没有极度谨慎的情况下做危险、不安全的事情,那么谨慎的方法可能看起来是这样的:

var='{old,new}'
for f in "file 1.txt" "file 2.txt" "file 3.txt" "file 4.txt"; do
  printf -v cmd 'mv %sname/%q' "$var" "$name" && eval "$cmd"
done

在这里,我们使用
%s
替换大括号扩展(手写的、受信任的代码),并使用
%q
替换(可能是不受信任的)文件名。

您不希望在不需要时评估变量的内容。 替代方法之一是编写函数

function oldnewname { mv oldname/"$1" newname/"$1" }
oldnewname "file 1.txt"
oldnewname "file 2.txt"
oldnewname "file 3.txt"
oldnewname "file 4.txt"
当名称为动态时,可以更改函数

function oldnew { mv old"$1"/"$2" new"$1"/"$2" }
oldnew name "file 1.txt"
oldnew name "file 2.txt"
oldnew name "file 3.txt"
oldnew name "file 4.txt"
编辑: 因为我迁移到Linux和Bash,所以忽略了POSIX。正如@Charles所评论的,更具可移植性的是

oldnewname()
{
  mv oldname/"$1" newname/"$1"
}

您不希望在不需要时评估变量的内容。 替代方法之一是编写函数

function oldnewname { mv oldname/"$1" newname/"$1" }
oldnewname "file 1.txt"
oldnewname "file 2.txt"
oldnewname "file 3.txt"
oldnewname "file 4.txt"
当名称为动态时,可以更改函数

function oldnew { mv old"$1"/"$2" new"$1"/"$2" }
oldnew name "file 1.txt"
oldnew name "file 2.txt"
oldnew name "file 3.txt"
oldnew name "file 4.txt"
编辑: 因为我迁移到Linux和Bash,所以忽略了POSIX。正如@Charles所评论的,更具可移植性的是

oldnewname()
{
  mv oldname/"$1" newname/"$1"
}

参数替换后发生的唯一扩展是字符串拆分和全局化。大括号展开发生在值展开之前。之所以如此,有令人信服的涉及安全性的原因(如果任意数据被解析为语法,您基本上永远无法在bash中编写处理具有不可信名称的文件的脚本)……因此,简短的回答是“出于充分的理由,您不能这样做,并试图找到解决办法(如
eval
)除非非常小心,否则将危及安全性”。参数替换后发生的唯一扩展是字符串拆分和全局绑定。大括号展开发生在值展开之前。之所以如此,有令人信服的涉及安全性的原因(如果任意数据被解析为语法,您基本上永远无法在bash中编写处理具有不可信名称的文件的脚本)……因此,简短的回答是“出于充分的理由,您不能这样做,并试图找到解决办法(如
eval
)除非非常小心,否则会危及安全。谢谢!你可以用一个漂亮的代码来解决我的问题。为什么在这里使用非POSIX函数声明语法?该方法是一种很好的方法,但是用于实现它的代码与我在Solaris和AIX环境中长期使用的
ksh
函数
有点不兼容。我应该重新考虑一下我的风格,使用类似的东西。谢谢!你可以用一个漂亮的代码来解决我的问题。为什么在这里使用非POSIX函数声明语法?该方法是一种很好的方法,但是用于实现它的代码与我在Solaris和AIX环境中长期使用的
ksh
函数
有点不兼容。我应该重新考虑一下我的风格,比如。谢谢你的解释和时间!谢谢你的解释和时间!