关于shell:bash脚本:循环参数

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。在调用脚本之后

1
2
3
1 ~
1 ~
1 ~


在for循环中使用"$@"

1
2
3
4
5
for i in"$@"
do
   sed -i.bak 's/~/~
/g'"$i"
done

尽管我不确定塞德是否在做你在这里描述的事情。


这就足够了:

1
2
3
4
for i do
  sed -i.bak 's/~/~
/g'"$i"
done

在这里,可移植的变体应该与任何符合POSIX的shellsed一起工作:

1
2
3
4
for i do
  sed 's/~/~
/g'"$i">"$i.bak" && cp"$i.bak""$i"
done

注:外壳for回路的in ...部分为可选。如果不使用,for默认选择所有参数(即"$@"),这正是您所期望的。


其他答案涵盖了你真正的问题。但有一件事值得说的是,当双报价时,$*$@在扩张方面的差异。医生,你几乎总是想要"$@"

"$*"扩展为一个字符串,其中包含所有参数,其中第一个字符为IFS。在实践中,这通常意味着所有参数都是一个由空格分隔的字符串。所以如果你的参数是file1.txtfile2.txtfile3.txt,那么"$*"把它作为一个东西交给循环,即file1.txt file2.txt file3.txt。当然,有一件事是不存在的。

"$@"扩展到每个参数,一次一个,作为单个"字"处理。这很好,因为它将把前面例子中的file1.txtfile2.txtfile3.txt正确地视为三个项目。循环将一次正确地接收一个。另外,"$@"是好的,因为即使文件名中有空格,也会得到正确的行为,因为循环将处理,例如filename 1filename 2filename 2 and a half作为三项,一项接一项。(通常情况下,shell将空格视为单词的结尾,因此对于shell,filename 1看起来像两个项目:filename1

当没有引用$@$*时,扩展所有位置参数的字。因此,在这种情况下,它们实际上是相同的(这两个都是坏主意,因为它们不会保护您免受奇怪命名的文件的攻击)。

这里有一个很好的可视化的所有可能性:http://wiki.bash hackers.org/scripting/posparams mass用法。