追加到函数的最后(或第 n)行(使用 awk/sed)
Append to last (or n-th) line of function (using awk/sed)
最好使用 awk、sed 或类似的工具,我该如何实现 append_last_line
,例如。在函数体的 last 行附加一些东西,它可以在给定文件的任何地方?
# file.sh
foo ()
{
echo "bar"
}
$ append_last_line 'foo' 'echo "baz"' file.sh
# file.sh
foo ()
{
echo "bar"
echo "baz"
}
第 n-th 行呢?
# file.sh
foo ()
{
echo "bar"
echo "baz"
}
$ append_nth_line 1 'foo' 'echo "qux"' file.sh
# file.sh
foo ()
{
echo "baz"
echo "qux"
echo "bar"
}
让您入门的东西:
awk -v name=foo -v num=2 -v what='echo "qux"' '
# Print the line and read next line and handle getline error
function print_getline() {
print;
if (getline <= 0) exit 1;
}
[=10=] ~ name "[[:space:]]*()"{ # match the function followed by ()
while ([=10=] !~ "{") { print_getline(); } # wait for {
while (num--) { print_getline(); } # omit num count lines
print what; # add the line you want to add
}
{ print } # print all other lines
' <<EOF
# file.sh
foo ()
{
echo "bar"
echo "baz"
}
EOF
将输出:
# file.sh
foo ()
{
echo "bar"
echo "qux"
echo "baz"
}
网上对awk
的介绍很多。 awk
是一门伟大的语言。但是,如果您打算编写完整的 shell 语言解析器来处理所有极端情况(即 echo "foo () {"
不是函数定义...),请考虑使用更强大的语言,如 perl 或 python.
显然,您为此编写的任何脚本都是脆弱的,因为您需要一个用于编写目标文件的语言的解析器才能稳健地完成这项工作,但这里有一些东西可以用您想要的示例来做提供:
$ cat tst.sh
#!/usr/bin/env bash
(( $# > 3 )) && { tgtLineNr=; shift; }
tgtFunc=
newText=
shift 2
awk -v tgtLineNr="$tgtLineNr" -v tgtFunc="$tgtFunc" -v newText="$newText" '
state == "gotFuncBeg" {
if ( /^}/ ) { state = "gotFuncEnd" }
if ( (lineNr++ == tgtLineNr) || ((state == "gotFuncEnd") && !tgtLineNr) ) {
sub(/[^[:space:]].*/,"",indent)
print indent newText
}
if ( NF ) { indent = [=10=] }
}
(state == "gotFuncName") && /^{/ {
state = "gotFuncBeg"
lineNr = 0
}
/^[[:alpha:]_][[:alnum:]_]*[[:space:]]*\(/ {
thisFunc = [=10=]
sub(/[[:space:]]*\(.*/,"",thisFunc)
state = (thisFunc == tgtFunc ? "gotFuncName" : "")
}
{ print }
' "$@"
$ cat file
# file.sh
foo ()
{
echo "bar"
echo "baz"
}
$ ./tst.sh 'foo' 'echo "qux"' file
# file.sh
foo ()
{
echo "bar"
echo "baz"
echo "qux"
}
$ ./tst.sh 1 'foo' 'echo "qux"' file
# file.sh
foo ()
{
echo "bar"
echo "qux"
echo "baz"
}
感谢您提供的精彩脚本,伙计们!我一定会深入研究它们。
我最终根据来自 @rturrado
的 编写了这个脚本
$ cat append-nth-line.sh
#!/bin/bash
IFS=''
function_name=
nth=
append=
out=
declare function_start_line
declare function_end_line
search="on"
i=1
while read -r line; do
echo $line >>tmp1
if [[ $(echo $line | xargs) =~ ^($function_name[[:space:]]*?\(\)) ]]; then
function_start_line=$i
fi
if [ $function_start_line ]; then
if [[ $(echo $line | xargs) =~ ^} && $search = "on" ]]; then
function_end_line=$i
search="off"
fi
fi
i=$(($i + 1))
done
if [[ "$nth" =~ ^- ]]; then
find=$(($function_end_line + $nth))
else
find=$(($function_start_line + $nth))
fi
i=1
cat tmp1 |
while read -r line; do
echo $line >>tmp2
if [[ $i = $find ]]; then
indent=$(echo $line | grep -o ^'[[:space:]]*')
if [[ ! "$nth" =~ ^- && $(echo $line | xargs) =~ \{|then|else|do ]]; then
indent="$indent "
fi
echo "$indent$append" >>tmp2
fi
i=$(($i + 1))
done
rm tmp1
chmod +x tmp2
mv tmp2 $out
$ cat file.sh
foo()
{
echo "bar"
}
$ append_nth_line.sh "foo" -1 'echo "baz"' file.sh < file.sh
$ cat file.sh
foo()
{
echo "bar"
echo "baz"
}
$ append_nth_line.sh "foo" 1 'echo "qux"' file.sh < file.sh
$ cat file.sh
foo()
{
echo "qux"
echo "bar"
echo "baz"
}
我还有一些极端情况需要解决,但这个或您的脚本就可以了。
欢迎反馈。
… sed or similar
使用ed:
set -- filename funcname -1 ' echo "quux"'
printf '%s\n' '/^'""'[ (]/;#' '/^}/;#' ""a "" . w q | ed -rs ""
查找 funcname
,然后查找尾随 }
,在
}
(-1) 前一行,最后保存编辑后的文件。
最后一行调用 -1,倒数第三行调用 -3 ...
这可能对你有用(GNU sed & bash):
# append_last_line 'foo' 'echo "baz"' file.sh
append_last_line (){ sed '/^''\s*()/{:a;h;n;/^}$/!ba;x;s/\S.*/'""'/p;x}' ""; }
# append_nth_line 2 'foo' 'echo "baz"' file.sh N.B. n must be natural number > 0
append_nth_line (){ sed -E '/^''\s*\(\)/{n;n;:a;N;/^}/M!ba;s/(((\s*)[^\n]*(\n)){''})/&'""'/}' ""; }
最好使用 awk、sed 或类似的工具,我该如何实现 append_last_line
,例如。在函数体的 last 行附加一些东西,它可以在给定文件的任何地方?
# file.sh
foo ()
{
echo "bar"
}
$ append_last_line 'foo' 'echo "baz"' file.sh
# file.sh
foo ()
{
echo "bar"
echo "baz"
}
第 n-th 行呢?
# file.sh
foo ()
{
echo "bar"
echo "baz"
}
$ append_nth_line 1 'foo' 'echo "qux"' file.sh
# file.sh
foo ()
{
echo "baz"
echo "qux"
echo "bar"
}
让您入门的东西:
awk -v name=foo -v num=2 -v what='echo "qux"' '
# Print the line and read next line and handle getline error
function print_getline() {
print;
if (getline <= 0) exit 1;
}
[=10=] ~ name "[[:space:]]*()"{ # match the function followed by ()
while ([=10=] !~ "{") { print_getline(); } # wait for {
while (num--) { print_getline(); } # omit num count lines
print what; # add the line you want to add
}
{ print } # print all other lines
' <<EOF
# file.sh
foo ()
{
echo "bar"
echo "baz"
}
EOF
将输出:
# file.sh
foo ()
{
echo "bar"
echo "qux"
echo "baz"
}
网上对awk
的介绍很多。 awk
是一门伟大的语言。但是,如果您打算编写完整的 shell 语言解析器来处理所有极端情况(即 echo "foo () {"
不是函数定义...),请考虑使用更强大的语言,如 perl 或 python.
显然,您为此编写的任何脚本都是脆弱的,因为您需要一个用于编写目标文件的语言的解析器才能稳健地完成这项工作,但这里有一些东西可以用您想要的示例来做提供:
$ cat tst.sh
#!/usr/bin/env bash
(( $# > 3 )) && { tgtLineNr=; shift; }
tgtFunc=
newText=
shift 2
awk -v tgtLineNr="$tgtLineNr" -v tgtFunc="$tgtFunc" -v newText="$newText" '
state == "gotFuncBeg" {
if ( /^}/ ) { state = "gotFuncEnd" }
if ( (lineNr++ == tgtLineNr) || ((state == "gotFuncEnd") && !tgtLineNr) ) {
sub(/[^[:space:]].*/,"",indent)
print indent newText
}
if ( NF ) { indent = [=10=] }
}
(state == "gotFuncName") && /^{/ {
state = "gotFuncBeg"
lineNr = 0
}
/^[[:alpha:]_][[:alnum:]_]*[[:space:]]*\(/ {
thisFunc = [=10=]
sub(/[[:space:]]*\(.*/,"",thisFunc)
state = (thisFunc == tgtFunc ? "gotFuncName" : "")
}
{ print }
' "$@"
$ cat file
# file.sh
foo ()
{
echo "bar"
echo "baz"
}
$ ./tst.sh 'foo' 'echo "qux"' file
# file.sh
foo ()
{
echo "bar"
echo "baz"
echo "qux"
}
$ ./tst.sh 1 'foo' 'echo "qux"' file
# file.sh
foo ()
{
echo "bar"
echo "qux"
echo "baz"
}
感谢您提供的精彩脚本,伙计们!我一定会深入研究它们。
我最终根据来自 @rturrado
的$ cat append-nth-line.sh
#!/bin/bash
IFS=''
function_name=
nth=
append=
out=
declare function_start_line
declare function_end_line
search="on"
i=1
while read -r line; do
echo $line >>tmp1
if [[ $(echo $line | xargs) =~ ^($function_name[[:space:]]*?\(\)) ]]; then
function_start_line=$i
fi
if [ $function_start_line ]; then
if [[ $(echo $line | xargs) =~ ^} && $search = "on" ]]; then
function_end_line=$i
search="off"
fi
fi
i=$(($i + 1))
done
if [[ "$nth" =~ ^- ]]; then
find=$(($function_end_line + $nth))
else
find=$(($function_start_line + $nth))
fi
i=1
cat tmp1 |
while read -r line; do
echo $line >>tmp2
if [[ $i = $find ]]; then
indent=$(echo $line | grep -o ^'[[:space:]]*')
if [[ ! "$nth" =~ ^- && $(echo $line | xargs) =~ \{|then|else|do ]]; then
indent="$indent "
fi
echo "$indent$append" >>tmp2
fi
i=$(($i + 1))
done
rm tmp1
chmod +x tmp2
mv tmp2 $out
$ cat file.sh
foo()
{
echo "bar"
}
$ append_nth_line.sh "foo" -1 'echo "baz"' file.sh < file.sh
$ cat file.sh
foo()
{
echo "bar"
echo "baz"
}
$ append_nth_line.sh "foo" 1 'echo "qux"' file.sh < file.sh
$ cat file.sh
foo()
{
echo "qux"
echo "bar"
echo "baz"
}
我还有一些极端情况需要解决,但这个或您的脚本就可以了。
欢迎反馈。
… sed or similar
使用ed:
set -- filename funcname -1 ' echo "quux"'
printf '%s\n' '/^'""'[ (]/;#' '/^}/;#' ""a "" . w q | ed -rs ""
查找 funcname
,然后查找尾随 }
,在
}
(-1) 前一行,最后保存编辑后的文件。
最后一行调用 -1,倒数第三行调用 -3 ...
这可能对你有用(GNU sed & bash):
# append_last_line 'foo' 'echo "baz"' file.sh
append_last_line (){ sed '/^''\s*()/{:a;h;n;/^}$/!ba;x;s/\S.*/'""'/p;x}' ""; }
# append_nth_line 2 'foo' 'echo "baz"' file.sh N.B. n must be natural number > 0
append_nth_line (){ sed -E '/^''\s*\(\)/{n;n;:a;N;/^}/M!ba;s/(((\s*)[^\n]*(\n)){''})/&'""'/}' ""; }