正如goldilocks的评论和人类参考文献所描述的那样,
shift
重新分配位置参数($1
,$2
等),以便$1
采用的旧值$2
,
$2
采用的值$3
等。*$1
丢弃
旧的值。($0
未更改。)执行此操作的某些原因包括:
- 它使您可以更轻松地访问第十个参数(如果有)。
$10
不起作用–它被解释为与$1
串联0
(因此可能会产生Hello0
)。在a之后shift
,第十个参数变为$9
。(但是,在大多数现代Shell中,您可以使用${10}
。)
- 正如Bash初学者指南所演示的那样,它可用于循环遍历参数。恕我直言,这很笨拙;
for
对此要好得多。
- 就像您的示例脚本一样,它使您可以轻松地以相同的方式处理所有参数,除了少数几个。例如,在脚本中,
$1
和$2
是文本字符串,而$3
and所有其他参数是文件名。
这就是它的播放方式。假设您的脚本被调用Patryk_script
,并且被称为
Patryk_script USSR Russia Treaty1 Atlas2 Pravda3
脚本看到
$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = Atlas2
$5 = Pravda3
该语句ostr="$1"
将变量设置ostr
为USSR
。第一条shift
语句按如下所示更改位置参数:
$1 = Russia
$2 = Treaty1
$3 = Atlas2
$4 = Pravda3
该语句nstr="$1"
将变量设置nstr
为Russia
。第二条shift
语句按如下方式更改位置参数:
$1 = Treaty1
$2 = Atlas2
$3 = Pravda3
然后for
循环变化USSR
($ostr
)来Russia
($nstr
在文件中)Treaty1
,Atlas2
和Pravda3
。
脚本存在一些问题。
以$ @归档;做
如果脚本被调用为
Patryk_script苏联俄罗斯条约1“世界地图集2” Pravda3
它看到
1美元=苏联
2美元=俄罗斯
$ 3 =条约1
4美元=世界地图集2
5美元= Pravda3
但是,因为$@
没有加引号,在太空World Atlas2
中没有报价,并且for
循环认为它有四个文件:Treaty1
,World
,Atlas2
,和Pravda3
。这应该是
用于“ $ @”中的文件;做
(在参数中引用任何特殊字符)或简单地
对于文件
(相当于更长的版本)。
eval“ sed's /” $ ostr“ /” $ nstr“ / g'$ file”
不必将其设置为eval
,并且将未经检查的用户输入传递给eval
会很危险。例如,如果脚本被调用为
Patryk_script“'; rm *;'”俄罗斯条约1 Atlas2 Pravda3
它会执行rm *
!如果脚本可以比调用它的用户更高的特权运行,这将是一个大问题。例如,它是否可以通过sudo
Web界面运行或从Web界面调用。如果仅在目录中以自己的方式使用它,那么可能就没有那么重要了。但是可以更改为
sed“ s / $ ostr / $ nstr / g”“ $ file”
这仍然有一些风险,但是风险要轻得多。
if [ -f $file ]
,> $file.tmp
而mv $file.tmp $file
应该是if [ -f "$file" ]
,> "$file.tmp"
和mv "$file.tmp" "$file"
分别处理,可能在他们的空间(或其他奇怪的字符)的文件名。(该eval "sed …
命令还会破坏其中包含空格的文件名。)
* shift
带有一个可选参数:一个正整数,它指定要移动多少个参数。默认值为一(1
)。例如,shift 4
使$5
成为$1
,
$6
成为$2
,等等。(请注意,《Bash初学者指南》中的示例是错误的。)因此,可以将脚本修改为:
ostr="$1"
nstr="$2"
shift 2
可能会更清楚。
结束语 /警告:
Windows命令提示符(批处理文件)语言还支持SHIFT
命令,该shift
命令与Unix shell中的命令基本上具有相同的功能,但有一个显着的不同,我将隐藏该代码,以防止人们对此感到困惑:
- 像这样的命令
SHIFT 4
是错误,产生“对SHIFT命令无效的参数”错误消息。
SHIFT /n
,其中n
为0到8之间的整数是有效的-但它不会移位times。它从第n 个参数开始偏移一次。因此, 导致(第五个参数)变为,依此类推,仅将参数0到3保留下来。n
SHIFT /4
%5
%4,
%6
%5
pushd
和popd
)。