bash script: looping over arguments
我写了一个脚本(replace.sh),用~替换了~。我想知道如何用多个参数调用这个脚本。
1 2 3 4 5 6 7
| #!/bin/bash
for i in"$*"
do
sed 's/~/~
/g'"$i"
done |
例如,我想调用./replace.sh text1 text2。它不能阅读
文本1的内容为:1~1~1。在调用脚本之后
- 有关$*和$@之间的区别,请参阅此处:mywiki.wooledge.org/bashguide/…。它很微妙,但对于shell脚本编写非常重要。
在for循环中使用"$@":
1 2 3 4 5
| for i in"$@"
do
sed -i.bak 's/~/~
/g'"$i"
done |
尽管我不确定塞德是否在做你在这里描述的事情。
- 正是我需要的!至于sed,应该是's/~//g'
- 不用in"$@"就可以节省一些按键…
- @Jiliagre我认为这是一个简明扼要的例子。很多人都不知道单凭for i就意味着in"$@"意味着什么。这是一个额外的7个字符的类型,但在明确的回报是巨大的。
- 授予。许多人都不知道in"$@"与通常的ìn $*相比意味着什么。这就是为什么我更喜欢建议空的表格,这是我更容易记住的。
这就足够了:
1 2 3 4
| for i do
sed -i.bak 's/~/~
/g'"$i"
done |
在这里,可移植的变体应该与任何符合POSIX的shell和sed一起工作:
1 2 3 4
| for i do
sed 's/~/~
/g'"$i">"$i.bak" && cp"$i.bak""$i"
done |
注:外壳for回路的in ...部分为可选。如果不使用,for默认选择所有参数(即"$@"),这正是您所期望的。
- 请不要推荐没有后缀的-i。这意味着没有备份。没有备份->很可能是触摸。另外,也许可以解释一下在没有in 的shell脚本中使用for循环意味着什么?
- 答案更新为更可移植的解决方案(posix),该解决方案处理备份备注,尽管运行脚本时,多个脚本将导致xxx.bak.bak文件,而第一次运行将覆盖潜在的现有备份…
- @Jiliagre+1感谢您的更新/澄清。(我听过你多次跑步,但我仍然认为对新的编剧来说总是值得一提的。我的宠物问题,因为我第一次学习Perl一行程序。
- 非常好的细节;没有备份的编辑会带来伤害。
其他答案涵盖了你真正的问题。但有一件事值得说的是,当双报价时,$*和$@在扩张方面的差异。医生,你几乎总是想要"$@"。
"$*"扩展为一个字符串,其中包含所有参数,其中第一个字符为IFS。在实践中,这通常意味着所有参数都是一个由空格分隔的字符串。所以如果你的参数是file1.txt、file2.txt和file3.txt,那么"$*"把它作为一个东西交给循环,即file1.txt file2.txt file3.txt。当然,有一件事是不存在的。
"$@"扩展到每个参数,一次一个,作为单个"字"处理。这很好,因为它将把前面例子中的file1.txt、file2.txt和file3.txt正确地视为三个项目。循环将一次正确地接收一个。另外,"$@"是好的,因为即使文件名中有空格,也会得到正确的行为,因为循环将处理,例如filename 1、filename 2、filename 2 and a half作为三项,一项接一项。(通常情况下,shell将空格视为单词的结尾,因此对于shell,filename 1看起来像两个项目:filename和1。
当没有引用$@和$*时,扩展所有位置参数的字。因此,在这种情况下,它们实际上是相同的(这两个都是坏主意,因为它们不会保护您免受奇怪命名的文件的攻击)。
这里有一个很好的可视化的所有可能性:http://wiki.bash hackers.org/scripting/posparams mass用法。
- 我认为你应该在答案中加上双引号,因为这两个变量在未加引号时也有意义(实际上意义相同)。您可能还希望在答案中包含未引用的含义。说明:$*展开为单个字符串是不正确的;应该是"$*"展开为单个字符串…是的,您在上一段中提到了双引号,但在下一段中省略它们会误导您。
- @你说得对。不知道我怎么了。我应该包括报价,我会提到未报价的版本。
- 嗨,Telemachus。我有种感觉"$*"确实扩展到了一个字符串,感谢您确认和解释幕后发生的事情。