首页 > 解决方案 > 如何用替换处理 Tcl 脚本中的 sed

问题描述

我正在编写一个 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作为命令进行评估。

知道我应该在这里做什么来完成这项工作吗?

谢谢。

标签: sedtcl

解决方案


您首先应该确定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在方便的时候通过 ing 列表来解决这个问题,也许您还想进一步按摩要插入的文本。这就是所有的改进...

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
}

推荐阅读