使用参数化文件名将多个文件一次移动到目标目录的Unix命令?

cfh9epnr  于 2023-03-22  发布在  Unix
关注(0)|答案(3)|浏览(238)

我试图移动特定的文件名一次从一个目录到其他使用单一的命令行。我已经捕获的文件名(不完整的路径)在一个变量如下所示,它可能有100至1000个文件名。

var=“M1.txt,A2.dat,T300.log”

我尝试以下命令其工作mv /home/rrajendr/test1/{M1.txt,A2.dat,T300.log} /home/rrajendr/test 2/
如果参数化mv /home/rrajendr/test1/{"$var”} /home/rrajendr/test 2/,则无法使用相同的方法
Error mv:cannot stat/home/rrajendr/test1/{M1.txt,A2.dat,T300.log}:无此文件或目录
它寻找一个文件名,就像这个“{M1.txt,A2.dat,T300.log}”一样,它没有解释为单个文件名。这里缺少了一些东西,请让我知道
我尝试了以下选项,但没有工作
mv /home/rrajendr/test1/ echo $var -t /home/rrajendr/test2/
mv /home/rrajendr/test1/{$var}
mv /home/rrajendr/test1/{ echo $var }
我寻找此选项的原因
1.我的源路径是固定的,我不想定义背靠背与完整的限定符为每个文件名,因为我有100个文件。
1.我不想来回切换到文件目录(cd /home/rrajendr/test1/),因为我正在执行其他操作,如aws cli操作和snow cli命令。
1.我已经在一个变量中存储了100个文件名,如字符串var=“M1.txt,A2.dat,T300.log”
1.不想像python等程序那样,在shell中使用for或while循环,也不使用xargs
1.使用单个命令行启动多个文件移动

pqwbnv8z

pqwbnv8z1#

如果你正在创建文件列表,并且知道列表中没有有趣的字符,我会使用eval

cmd="mv /home/rrajendr/test1/{$var} /home/rrajendr/test2"
eval $cmd

甚至

eval "mv /home/rrajendr/test1/{$var} /home/rrajendr/test2"

注意,brace expansion 在2023年还不是POSIX shell的特性。这只在你的sh是bash或zsh或任何其他支持brace expansion的shell时才有效。
我认为正确的方法是循环或使用xargs,这样可以减少中断的机会。为什么要避免这样做呢?移动文件从来都不是瓶颈。

zf9nrax1

zf9nrax12#

在GNU Bash、Z Shell和Korn Shell中,大括号扩展是在变量替换之前完成的。这就是为什么尝试的命令会失败,因为大括号只看到字符串$var,而不是分配给它的值。
一个简单的解决方法是使用eval,但要注意**eval是邪恶的**(见下文)。
通常,当创建一个跟踪文件的变量时,建议使用数组而不是单个变量。在OP的情况下,这将导致以下任何解决方案:

file_list=( "M1.txt" "A2.dat" "T300.log" )
cd /path/to/old/dir; mv -t /path/to/new/dir -- "${file_list[@]}"
mv -t /path/to/new/dir -- "${file_list[@]/#//path/to/old/dir/}"
for _f in "${file_list[@]}"; do mv -- "/path/to/old/dir/${_f}" /path/to/new/dir; done
...

Eval是邪恶的:

disho6za

disho6za3#

对于包含逗号分隔的文件名列表的变量var,您可以执行以下操作:

( cd /home/rrajendr/test1 && { IFS=,; mv -i -- $var /home/rrajendr/test2; } )

POSIX shell在变量扩展期间执行字拆分。通常,引用变量以避免字拆分是一个很好的做法,但在这里我们可以通过设置IFS而不是引用来利用这一点,以便存储在var中的逗号分隔字符串在扩展时被拆分为多个文件名。
通过切换到源目录,我们不需要在文件名中包含它。我们使用&&来避免在cd失败时复制错误的文件。
正如Jens所指出的,设置IFS只对以下命令生效,因此我们将它们都 Package 在{ ... }中,以便将它们视为&&列表中的单个元素。
我们将--传递给mv,以防var包含可能被误解为选项的文件名。
我们将整个命令行 Package 在( ... )中,这样就不必显式地将cd返回到原始目录。
这个问题使用了绝对路径。如果没有,那么在执行cd之前,有必要计算目标的绝对路径。例如,如果命令在/home中运行并使用了相对路径,我们可以这样做:

( cd rrajendr/test1 && { IFS=,; mv -i -- $var "$(realpath rrajendr/test2)"; } )

相关问题