我有一个名为 的目录。我试图将其复制 4 次,DS1
因此我还有DS2
、DS3
和。DS4
DS5
我能够从终端使用以下命令并且它可以工作:
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
不支持括号扩展。
因此您可以:
- 使您的脚本成为一个
bash
脚本(或者成为一个支持括号扩展的其他 shell 的脚本,例如zsh
或ksh
)。 - 将脚本中的括号扩展替换为在 中有效的内容
dash
。
如果你想让你的脚本成为bash
脚本,请替换
#!/bin/sh
和:
#!/bin/bash
然后当像 一样运行时./scriptname
它将在 中运行bash
。如果您通过书写来运行脚本,sh scriptname
那么您必须使用bash scriptname
。
如果你想消除括号扩展,有几种替代方法。我建议seq
使用命令替换,这可能是括号扩展最常见的替代方法,它易于编写,并且很可能被其他人类读者理解。
{2..5}
你可以用 代替。$(seq 2 5)
由于它没有被引用——也就是说,因为它是$(
)
而不是"$(
)"
——场分裂(这bash
被称为单词拆分)对结果执行。只要您没有设置IFS
shell 变量,控制字段拆分为包含任意数字或不包含换行符的值,这将满足您的要求。
(通配符- 也叫文件名扩展, 也叫路径名扩展-- 也对不带引号的命令替换的结果执行,但输出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 标准并且不支持括号扩展。
因此你有两个选择:
- 将 shebang 更改为
#!/bin/bash
或另一个支持括号扩展的 shell。
或者
- 使用
#!/bin/sh
并{2..5}
替换$(seq 2 5)
。
还可以看看这个有趣的 Stack Overflow 问题,关于sh 和 Bash 之间的区别。