Pat*_*ryk 173 shell-script arguments
我遇到了这个脚本:
#! /bin/bash
if (( $# < 3 )); then
echo "$0 old_string new_string file [file...]"
exit 0
else
ostr="$1"; shift
nstr="$1"; shift
fi
echo "Replacing \"$ostr\" with \"$nstr\""
for file in $@; do
if [ -f $file ]; then
echo "Working with: $file"
eval "sed 's/"$ostr"/"$nstr"/g' $file" > $file.tmp
mv $file.tmp $file
fi
done
Run Code Online (Sandbox Code Playgroud)
他们使用的行的含义是什么shift
?我认为脚本应该至少与参数一起使用,所以......?
hum*_*ace 202
shift
是一个bash
内置的,它从参数列表的开头删除参数。鉴于提供给脚本的 3 个参数在$1
, $2
,中可用$3
,那么调用shift
将$2
生成新的$1
. Ashift 2
将移动两个使$1
新旧$3
。有关更多信息,请参见此处:
Sco*_*ott 47
正如金发姑娘的评论和人类的参考所描述的那样,
shift
重新分配位置参数($1
,$2
等),以便$1
采用 的旧值$2
,
$2
采用 的值$3
等。*
的旧值$1
被丢弃。($0
未更改。)这样做的一些原因包括:
$10
不起作用 - 它被解释为$1
与 a 连接0
(因此可能会产生类似Hello0
)。在 a 之后shift
,第十个参数变为$9
。(但是,在大多数现代 shell 中,您可以使用${10}
.)for
对此要好得多。$1
和$2
是文本字符串,而$3
和所有其他参数是文件名。所以这就是它的表现。假设你的脚本被调用Patryk_script
,它被称为
Patryk_script USSR Russia Treaty1 Atlas2 Pravda3
Run Code Online (Sandbox Code Playgroud)
脚本看到
$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = Atlas2
$5 = Pravda3
Run Code Online (Sandbox Code Playgroud)
该语句ostr="$1"
将变量设置ostr
为USSR
。第一条shift
语句更改位置参数如下:
$1 = Russia
$2 = Treaty1
$3 = Atlas2
$4 = Pravda3
Run Code Online (Sandbox Code Playgroud)
该语句nstr="$1"
将变量设置nstr
为Russia
。第二个shift
语句更改位置参数如下:
$1 = Treaty1
$2 = Atlas2
$3 = Pravda3
Run Code Online (Sandbox Code Playgroud)
然后for
循环将文件, , 和中的USSR
( $ostr
) 变为Russia
( $nstr
) 。Treaty1
Atlas2
Pravda3
脚本存在一些问题。
用于 $@ 中的文件;做
如果脚本被调用为
Patryk_script 苏联俄罗斯条约1“世界地图集2”真理报3
它看到
1 美元 = 苏联 2 美元 = 俄罗斯 3 美元 = 条约 1 4 美元 = 世界地图集 2 5 美元 = 真理报 3
但是,因为$@
没有被引用,所以空格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 界面运行或调用。如果您只是在您的目录中将其用作自己,那么这可能并不那么重要。但是可以改成
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 初学者指南中的示例是错误的。)因此您的脚本可以修改为
for file in $@; do
这可能被认为更清楚。
尾注/警告:
Windows 命令提示符(批处理文件)语言也支持一个SHIFT
命令,它的作用与shift
Unix shell 中的命令基本相同,但有一个显着区别,我将隐藏它以防止人们被它混淆:
- 类似的命令
SHIFT 4
是一个错误,产生“无效的 SHIFT 命令参数”错误消息。SHIFT /n
,其中n
是 0 到 8 之间的整数,是有效的——但它不会移动时间。它移动一次,从第n个参数开始。所以 导致(第五个参数)变成变成,依此类推,只留下参数 0 到 3。n
SHIFT /4
%5
%4,
%6
%5
最简单的解释是这样的。考虑以下命令:
/bin/command.sh SET location Cebu
/bin/command.sh SET location Cebu, Philippines 6014
Run Code Online (Sandbox Code Playgroud)
如果没有帮助,shift
您将无法提取位置的完整值,因为该值可能会变得任意长。当您移动两次时,argsSET
和location
会被删除,这样:
x="$@"
echo "location = $x"
Run Code Online (Sandbox Code Playgroud)
长时间盯着那个$@
东西。这意味着,它可以将完整的位置保存到变量中x
,尽管它有空格和逗号。总之,我们调用shift
,然后检索变量中剩下的值$@
。
更新
我在下面添加了一个非常短的片段,显示了它的概念和用途shift
,如果没有它,正确提取字段将非常非常困难。
#!/bin/sh
#
[ $# -eq 0 ] && return 0
a=$1
shift
b=$@
echo $a
[ -n "$b" ] && echo $b
Run Code Online (Sandbox Code Playgroud)
解释:在 后shift
,变量b应包含传入的其余内容,无论空格等。这[ -n "$b" ] && echo $b
是一种保护,这样我们仅在 b有内容时才打印b 。
归档时间: |
|
查看次数: |
223680 次 |
最近记录: |