多次创建脚本到 cp 目录

多次创建脚本到 cp 目录

我有一个名为 的目录。我试图将其复制 4 次,DS1因此我还有DS2DS3和。DS4DS5

我能够从终端使用以下命令并且它可以工作:

for i in {2..5}; do cp -r /home/test/DS1 "DS$i"; done

但是,当我将其输入到这样的脚本中时:

#!/bin/sh

for i in {2..5}; do cp -r /home/test/DS1 "DS$i"; done

它创建一个名为的目录,DS{2..5}而不是增量在 2 到 5 之间的目录。不明白我做错了什么。

答案1

{2..5}括号扩展. 括号扩展不是由 POSIX 标准化. 一些(但不是全部)广泛使用的伯恩风格shell 支持它。

您在 Ubuntu 终端中交互的 shell 是bash,除非您故意使用其他 shell。bash支持括号扩展。舍邦sh你的脚本是在 Ubuntu 上符号链接dash.dash不支持括号扩展。

因此您可以:

  1. 使您的脚本成为一个bash脚本(或者成为一个支持括号扩展的其他 shell 的脚本,例如zshksh)。
  2. 将脚本中的括号扩展替换为在 中有效的内容dash

如果你想让你的脚本成为bash脚本,请替换

#!/bin/sh

和:

#!/bin/bash

然后当像 一样运行时./scriptname它将在 中运行bash。如果您通过书写来运行脚本,sh scriptname那么您必须使用bash scriptname


如果你想消除括号扩展,有几种替代方法。我建议seq使用命令替换,这可能是括号扩展最常见的替代方法,它易于编写,并且很可能被其他人类读者理解。

{2..5}你可以用 代替。$(seq 2 5)由于它没有被引用——也就是说,因为它是$( )而不是"$( )"——场分裂(这bash被称为单词拆分)对结果执行。只要您没有设置IFSshell 变量,控制字段拆分为包含任意数字或不包含换行符的值,这将满足您的要求。

通配符- 也叫文件名扩展, 也叫路径名扩展-- 也对不带引号的命令替换的结果执行,但输出seq将不包含通配符 ?*, 或[,因此在这种情况下没有效果。)

seq注意不标准化由 POSIX 开发。它可以在任何 GNU/Linux 系统和一些其他类 Unix 操作系统上运行,但一些类 Unix 操作系统seq默认不安装(通常安装jot),因此不能保证它可以在所有类 Unix 操作系统上运行。

答案2

当你在终端中运行脚本时,你使用的 shell 很可能是 Bash。Bash 支持括号扩展,因此{2..5}扩展到序列2 3 4 5并且您的脚本按您期望的方式工作。

但是,当你将相同的脚本添加到文件时,它不起作用。这是由于舍邦您正在使用(#!/bin/sh),它告诉您的脚本在 sh shell 中运行,它符合 POSIX 标准并且不支持括号扩展。

因此你有两个选择:

  1. 将 shebang 更改为#!/bin/bash或另一个支持括号扩展的 shell。

或者

  1. 使用#!/bin/sh{2..5}替换$(seq 2 5)

还可以看看这个有趣的 Stack Overflow 问题,关于sh 和 Bash 之间的区别

相关内容