我有一个充满文件的目录。我的目标是将文本附加到文件的开头。每个文件开头的文本都是相同的。这是我的尝试
#!/bin/bash
for file in `find . -type f -executable`;do
sed '/\#!/bin/bash\/a Hello Word'
done
我的脚本除了崩溃什么也没做
答案1
#!/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 指定的功能。特别是-executable
主要的find
是POSIX 未指定。考虑使用-perm +700
代替。
同样在可移植性领域,在 GNU Sed 中使用a
不带以下\<newline>
序列的 Sed ( ) 的“append”命令可以工作,但不是标准的。
您依次将循环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' {} +
这个脚本有什么作用?它递归地搜索当前目录以查找设置了可执行位(所有者)的所有文件,并且对于每个此类文件,打印整个文件,并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 {} +
答案2
你想实现什么目标?要查找可执行脚本,请使用以下命令
find . -type f -perm /u+x,g+x,o+x | while read file
do
filename=$(echo ${file} | awk -F/ '{print $NF}')
echo "File Name : ${filename}"
done
如果您尝试在 shebang 行之后附加 Hello World,那么您的 sed 命令应该是
sed '/\#!/bin/bash/a Hello Word' ${file}
如果您想对文件本身进行更改,请在 sed 命令中添加 -i
答案3
find . -type f -executable -exec sed '/^#!\/bin\/bash/a Hello World' {} \;