我正在编写一个Tcl脚本,该脚本在匹配的行后面的文件中插入一些文本。以下是脚本中的基本代码。
set test_lists [list "test_1"\
"test_2"\
"test_3"\
"test_4"\
"test_5"
]
foreach test $test_lists {
set content "
'some_data/$test'
"
exec sed -i "/dog/a$content" /Users/l/Documents/Codes/TCL/file.txt
}
但是,当我运行此脚本时,它总是向我显示此错误:
dyn-078192:TCL l$ tclsh test.tcl
sed: -e expression #1, char 12: unknown command: `''
while executing
"exec sed -i "/dog/a$content" /Users/l/Documents/Codes/TCL/file.txt"
("foreach" body line 5)
invoked from within
"foreach test $test_lists {
set content "
'some_data/$test'
"
exec sed -i "/dog/a$content" /Users/l/Documents/Codes/TCL/file.txt
}"
(file "test.tcl" line 8)
它总是尝试以命令的方式来评估$content
中的第一个单词。
任何想法我应该在这里做什么才能使这项工作?
谢谢。
答案 0 :(得分:2)
您首先应准确确定 sed需要处理哪些字符。 (请参阅https://unix.stackexchange.com/questions/445531/how-to-chain-sed-append-commands,了解这为什么很重要...)它们可能是:
/dog/a\
'some_data/test_1'
这将使文件变为:
abc
dog
hij
进入
abc
dog
'some_data/test_1'
hij
如果这是您想要的,则可以进入第二阶段:将Tcl中的这些字符放入sed。
# NB: *no* newline here!
set content "'some_data/$test'"
# NB: there's a quoted backslashes and two quoted newlines here
exec sed -i "/dog/a\\\n$content\n" /Users/l/Documents/Codes/TCL/file.txt
在Tcl中引用时需要注意的几个地方之一是当您附近有反斜杠和换行符时。
为什么不直接在Tcl本身中执行文本转换?与原始代码相比,这可能会颠倒插入行的顺序。您可以通过在方便的时候lreverse
列出列表来解决此问题,也许您还想进一步细分要插入的文本。这就是所有的改进...
set test_lists [list "'some_data/test_1'"\
"'some_data/test_2'"\
"'some_data/test_3'"\
"'some_data/test_4'"\
"'some_data/test_5'"
]
set filename /Users/l/Documents/Codes/TCL/file.txt
set REGEXP "dog"
# Read in the data; this is good even for pretty large files
set f [open $filename]
set lines [split [read $f] "\n"]
close $f
# Search for first matching line by regular expression
set idx [lsearch -regexp $lines $REGEXP]
if {$idx >= 0} {
# Found something, so do the insert in the list of lines
set lines [linsert $lines [expr {$idx + 1}] {*}$test_lists]
# Write back to the file as we've made changes
set f [open $filename "w"]
puts -nonewline $f [join $lines "\n"]
close $f
}
答案 1 :(得分:0)
(扩展注释,不是答案)
在shell中运行此命令以阐明所需的输出:这是您想要的吗?
$ cat file.txt
foo
dog A
dog B
dog C
dog D
dog E
bar
$ for test in test_{1..5}; do content="some_data/$test"; sed -i "/dog/a$content" file.txt; done
$ cat file.txt
foo
dog A
some_data/test_5
some_data/test_4
some_data/test_3
some_data/test_2
some_data/test_1
dog B
some_data/test_5
some_data/test_4
some_data/test_3
some_data/test_2
some_data/test_1
dog C
some_data/test_5
some_data/test_4
some_data/test_3
some_data/test_2
some_data/test_1
dog D
some_data/test_5
some_data/test_4
some_data/test_3
some_data/test_2
some_data/test_1
dog E
some_data/test_5
some_data/test_4
some_data/test_3
some_data/test_2
some_data/test_1
bar