附加到文件

K.U*_*K.U 2 sed find shell-script files

我有一个装满文件的目录。我的目标是将文本附加到文件的开头。每个文件开头的文本都是相同的。这是我的尝试

#!/bin/bash                                                                                                                                                    

for file in `find . -type f -executable`;do                                                                                                                                 
    sed '/\#!/bin/bash\/a Hello Word'                                                                                                                                            


done
Run Code Online (Sandbox Code Playgroud)

我的脚本除了崩溃什么都不做

Wil*_*ard 5

#!/bin/bash

for file in `find . -type f -executable`;do
    sed '/\#!/bin/bash\/a Hello Word'
fi

done
Run Code Online (Sandbox Code Playgroud)

这个脚本有很多问题。


首先,它不是有效的 Bash 脚本,因为您fi没有相应的if.


在风格上(删除fi行后),我会删除之前的空行done并在do. 但这相对微不足道。


现在,至于最佳实践,您使用反引号代替命令替换,而不是推荐的现代形式$(...). 纯粹出于历史原因支持反引号,不推荐用于任何新脚本;看:


你有一个健壮性问题,因为你在循环输出——find一个非常糟糕的主意,完全没有必要。您的脚本将在包含空格或特殊字符的任何文件名上中断。看:


如果您希望脚本具有可移植性,则应尽可能坚持使用 POSIX 指定的功能。特别是POSIX 没有指定-executable主要的 to 。考虑改用。find-perm +700

同样在可移植性领域,在 GNU Sed 中使用“追加”命令到 Sed ( a) 而不遵循以下\<newline>顺序,但不是标准的。


您将循环中的file变量for依次设置为每个文件的名称(假设文件名中没有特殊字符或空格,这将导致file变量包含不是文件名的内容),但您实际上从未使用过file变量。

您的 Sed 命令没有提供任何要运行的文件,因此它将尝试在标准输入上运行。因此,当您运行脚本时,它只会等待输入。


您的 Sed 脚本本身不正确,这与它缺少要操作的文件名无关。

如果您/用作正则表达式的分隔符(这是最常见的),则需要反斜杠转义/正则表达式中出现的所有实例。命令中唯一将被读取为正则表达式/\#!/的部分是,其余部分(以 开头bin)将被解释为 Sed 命令。

相反,通常的解决办法是更换每/ 其他比最终的正则表达式的分隔符\/。(我看到你转义了最后一个斜线,应该转义。)

Sed 中有一个鲜为人知的功能您可以在这里利用它。 任何字符(反斜杠或换行符除外)都可以用作正则表达式分隔符,而不仅仅是使用斜杠。因此/#!\/bin\/bash/,您可以使用等效的地址,而不是用作 Sed 地址\:#!/bin/bash:


现在,如果您已经处理了以上所有要点,您将拥有一个可以工作的脚本。它可能不会做你想让它做的事情,但它实际上会做一些事情。这样的脚本看起来像这样:

#!/bin/bash

find . -type f -perm -700 -exec sed '\:#!/bin/bash:a\
Hello World' {} +
Run Code Online (Sandbox Code Playgroud)

这个脚本有什么作用?它递归地在当前目录中搜索所有设置了可执行位的文件(对于所有者),并且对于每个这样的文件,打印整个文件,并在Hello World包含文本的任何行之后附加文本#!/bin/bash

Sed 实际上并不是为就地编辑文件而设计的;它是流编辑器。GNU Sed 将允许您使用-i开关就地编辑文件,但我只会使用标准工具ex进行文件编辑。


但这里还有一点。如果您想Hello World在 Bash 脚本中添加该行,它实际上不会执行任何操作,因为Hello它不是有效的命令名称。也许您想要的是在 Bash 脚本中打印文本“Hello World”,换句话说,添加echo "Hello World,这可能是有意义的。

现在我们进入更准确地阐明您的脚本该做什么的领域。


最终剧本

所以我对这个脚本的规范的更准确的陈述是:

  • 该脚本应在当前目录(或递归的任何子目录)中查找所有常规文件,这些文件为所有者设置了可执行位。
  • 对于每个这样的文件,脚本将检查文件的第一行是否完全等于 string #!/bin/bash
  • 仅对于具有此确切第一行的文件,脚本应echo "Hello World"在文件的第一行之后插入确切的 text ,后跟换行符。(此更改应保存到文件中,而不是打印到标准输出中。)

这是一个匹配这些确切规范的脚本,仅使用 POSIX 工具和功能:

#!/bin/sh

find . -type f -perm -700 -exec sh -c '
  for f
  do
    head -n 1 "$f" | grep -qFx "#!/bin/bash" &&
      printf "%s\n" "1a" "echo \"Hello World\"" . x | ex "$f"
  done
' find-sh {} +
Run Code Online (Sandbox Code Playgroud)