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)
我的脚本除了崩溃什么都不做
Run Code Online (Sandbox Code Playgroud)#!/bin/bash for file in `find . -type f -executable`;do sed '/\#!/bin/bash\/a Hello Word' fi done
这个脚本有很多问题。
首先,它不是有效的 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
,这可能是有意义的。
现在我们进入更准确地阐明您的脚本应该做什么的领域。
所以我对这个脚本的规范的更准确的陈述是:
#!/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)