【问题标题】:Append string of text to lines containing another string of text in bourne and bash在 bourne 和 bash 中将文本字符串附加到包含另一个文本字符串的行
【发布时间】:2015-08-27 19:22:12
【问题描述】:

我与许多在 OSX 上使用可怕的 XCode 的开发人员一起工作!更重要的是,他们需要在其构建代理上拥有多个版本,并在它们之间切换以构建与所述版本紧密耦合的旧代码! (我知道,这不是我的选择!)无论如何,为了让这种情况保持清醒,我在他们的构建上做了一个小报告,显示了

(a) /Applications 下的 XCode 是什么,使用命令:

$ find /Applications -name Xcode\* -maxdepth 1 -type d

给出如下输出:

/Applications/Xcode.app
/Applications/Xcode6.1.1.app

...和... (b) 'xcode-select' 工具已将其系统设置为使用哪个 Xcode,使用以下命令:

$ xcode-select -p | sed 's#/Contents/Developer##g'

( xcode-select 给出的输出,例如/Applications/Xcode.app/Contents/Developer/Applications/Xcode6.1.1.app/Contents/Developer 取决于哪个正在使用)

无论如何,我希望做的是整理这份报告。我希望不是首先输出系统上的一组文件夹,然后是设置要使用的文件夹,而是我可以在附加箭头时只输出由 find 生成的列表,或者<-- , <--Selected-Version-- 或类似的东西,到包含文本字符串的任何行的末尾/匹配给定的给定正则表达式。

尽管解决这个问题会很好,因为我总是尝试制作可以重复使用的通用代码,但我希望制作一个可以在类似上下文中重复使用的函数,如果这不会使整个想法不可行的话。

我的尝试如下:

appendArrowToMatchingLines ()
{
    local SEARCHstr
    local TEXT_BUFFERstr
    # Have we got more than one argument, but not exactly two
    if [ "$#" -gt "1" ] && [ "$#" -ne "2" ]
    then
        printf -v SEARCHstr "%q" "${1}"
        shift
        printf -v TEXT_BUFFERstr "%q" "$@"
        shift $#
    # Have we got exactly two arguments?
    elif [ "$#" -eq "2" ]
    then
        printf -v SEARCHstr "%q" "${1}"
        shift
        printf -v TEXT_BUFFERstr "%q" "${1}"
        shift
    # Third form, we must be streaming from STD_IN
    else
        printf -v SEARCHstr "%q" "${1}"
        printf -v TEXT_BUFFERstr "%q" "$( cat - )"
    fi
    printf "%s" "${TEXT_BUFFERstr}" | sed "/${SEARCHstr}/ s/$/<--/"
}

但是,不幸的是,这不起作用:(任何有关构建“将箭头附加到匹配行”功能的帮助将不胜感激!

另一个角度,如果我可以在没有缓冲的情况下做到这一点,那就更理想了,我见过类似的东西:

$ find . -name test.txt -exec sed -i '/PATTERN/ s/)$/); /' '{}' \;

在论坛中,他们建议他们可以在一个流中做类似的事情,尽管我也无法让它工作,而且我真的不知道从哪里开始! :)

再次感谢了解 sed/awk 世界的人的任何帮助!

【问题讨论】:

  • 没有 sed/awk。有 sed,也有 awk。 2 个完全独立的工具,具有自己的语法、用途等。当你想在一行上替换一些文本时,你可以使用 sed。当你想做更多的事情时,你可以使用 awk。你永远不会做的是编写一个 shell 脚本来完成一些工作并调用 sed 来完成其他工作。如果您只是发布一些清晰的示例输入和预期的输出,我们可以向您展示如何编写简洁的 awk 脚本来执行您想做的任何事情。

标签: regex xcode bash awk sed


【解决方案1】:

以下函数会将作为第二个参数提供的字符串附加到与第一个参数匹配的行:

# Append $2 to lines matching $1
function str_append() {
    [ $# -lt 2 ] && return 2
    local search=$1; local suffix=$2

    # Safely escape the $search variable for use in sed LHS (search pattern)
    search=$(printf -- '%s\n' "$search" | sed 's/[[\.*^$(){}?+|/]/\\&/g')   
    # escape special symbols '&', '/' and '\' in sed RHS (replacement)
    suffix=$(printf -- '%s\n' "$suffix" | sed 's/[\&/]/\\&/g')

    # Append $suffix to lines matching $search
    sed "/$search\+/s/$/${suffix}/"
}

当然,为了使该函数可用于命令行,您必须将其放置在您的环境中加载的文件中,例如 ~/.bashrc 或 ~/.bash_profile 文件中。那么:

要为所有匹配“file_pattern”的行添加一个箭头,运行:

find . -name '*.txt' | str_append "file_pattern" " <--"

find输出的所有行添加一个箭头运行:

find . -name '*.txt' | str_append "." " <--"

上述函数将输出所有行,包括匹配搜索字符串的行和不匹配的行。为了只输出匹配的行并在它们后面附加一个箭头,运行:

find . -name '*.txt' | grep 'file_pattern' | str_append '.' ' <--'

或者,如果您希望将此行为作为默认行为,请将 sed 行更改为:

sed -n "/$search\+/s/$/${suffix}/p"

-n : 默认情况下不打印输入行
/p : 如果我们有匹配则打印行

【讨论】:

  • 太好了,非常感谢!虽然,我实际上无法让它工作:(复制命令的输出,我想在使用 echo:echo "/Applications/Xcode.app /Applications/Xcode6.1.1.app" 的同时附加 | str_append "." " &lt;--"| str_append "/Applications/Xcode.app" " &lt;--" 甚至 | str_append "\/Applications\/Xcode.app" 只是似乎不起作用 :( 我使用的是 OSX。你有打开或关闭任何特殊的 shell 选项吗?
  • 输入应该由多行组成,如您的find 示例。您的 echo 示例仅输出一行,因此在整行中添加箭头是没有意义的。您可以改用printf。例如。 printf '%s\n%s' "/Applications/Xcode.app" "/Applications/Xcode6.1.1.app" | str_append "." "&lt;--" 。我还编辑了这个函数,让它也可以使用包含斜杠和其他特殊符号的字符串作为搜索字符串,所以现在你的 | str_append "/Applications/Xcode.app" " &lt;--" 应该可以工作了。如果还是不行,请告诉我是否有任何错误信息。
  • 还再次编辑了函数,以删除“bash-isms”。现在所有的变量转义都是用 sed 完成的。请尝试使用新版本并告诉我这是否适合您。
【解决方案2】:

将文本附加到匹配的行只是:

$ cat file
a
b
c

$ awk '/b/{$0 = $0 " <--- here is b"} 1' file
a
b <--- here is b
c

如果您需要其他内容,请编辑您的问题以显示清晰、精确、可测试的示例输入和预期输出。

在下面写下你的评论:

$ awk -v var=" <--- here is b" '/b/{$0 = $0 var} 1' file
a
b <--- here is b
c

$ var=" <--- here is b"
$ awk -v var="$var" '/b/{$0 = $0 var} 1' file
a
b <--- here is b
c

【讨论】:

  • 这太棒了,我认为这正是我所需要的,但是,我正在尝试稍微修改以允许将箭头字符串作为变量传递,但我一定犯了一些愚蠢的错误因为我无法让它工作:(我已经尝试过awk -v VAR="${VAR}" '/b/{$0 = $0 VAR} 1'awk '/b/{$0 = $0 "${VAR}"} 1',甚至awk '/b/{$0 = $0 '"${VAR}'"} 1',知道我在搞砸什么吗?
  • 不,您的第一个命令应该可以正常工作。永远不要尝试其他 2 - awk 不是 shell,因此您不能将 shell 变量用作 awk 脚本中的变量,并且尝试扩展 shell 变量以成为 awk 脚本本身的一部分会产生各种问题。我编辑了我的答案以显示两种方法。
猜你喜欢
  • 2023-02-21
  • 2014-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多