【问题标题】:Awk to replace single quoteawk 替换单引号
【发布时间】:2010-02-25 09:29:06
【问题描述】:

我想用include(' 替换一组文件中的所有include('./。我正在尝试按如下方式使用 awk:

awk '{gsub("include\('"'"'./", "include\('"'"'", $0); print > FILENAME}' *.php

它向我抛出了这个错误。

awk: (FILENAME=xyz.php FNR=1) fatal: Unmatched ( or \(: /include('.//

任何帮助将不胜感激。

【问题讨论】:

  • 是 awk 出于某种原因的特定要求吗?你真的应该使用 sed 。 sed -i 's/include(\'.\// include(\'/g' *.php
  • sed, awk, 两者都能胜任。
  • 您尝试过这里的文档吗?这样你就不必费心逃避

标签: unix shell awk


【解决方案1】:

@OP,您可以尝试使用八进制代码作为单引号(\047)和正斜杠(\057),例如

$ cat file
include('./
$ awk '{gsub(/include\(\047\.\057/ , "include(\047" ) }1' file
include('

【讨论】:

    【解决方案2】:

    这可行(在“打印”上没有 I/O 重定向):

    awk '{gsub(/include\('"'"'.\//, "include\('"'"'", $0); print }' # Wrong
    awk '{gsub(/include\('"'"'.\//, "include('"'"'", $0); print }'  # Right
    

    它映射这个输入:

    include('./abc')
    include('x/abc')
    

    到:

    include('abc')
    include('abc')
    

    根据经验,正则表达式似乎必须在斜杠内;替换字符串必须是常规字符串。您需要将“.”映射到“\.”以停止第二次替换。

    我对这个解释不太满意。 MacOS X 上 'awk' 的手册页说:

    /re/ 是一个常量正则表达式;任何字符串(常量或变量)都可以用作正则表达式,但模式中孤立正则表达式的位置除外。

    因此,理论上,您使用的字符串形式应该可以工作。根据经验,它没有。我收到的错误消息与您对代码所做的错误消息基本相同。而且你得到了正确的 shell 引号,这很重要。

    有时 Perl 可能更容易(因为您可以选择任意分隔符来标记正则表达式的边界):

    perl -pe "s%include\('\./%include('%g"
    

    【讨论】:

    • 此命令有效,但仅适用于包含一个或两个类似类型语句的非常简单的文件...在一个包含许多单引号和斜线的足够大的文件中,它似乎会搞乱一切。我也得到这个错误:awk:警告:转义序列\(' treated as plain ('
    • @GeekTantra:这是你需要使用脚本文件的地方:'awk -f file *.php'。然后,您不必与 shell 对引号的解释以及 awk 对引号的解释作斗争,这让生活变得更加轻松。重新警告:MacOS 'awk' 没有给出它,但是替换字符串中括号前面的反斜杠是不需要的 - 你的 'awk' 是正确的。
    • gsub 中使用双引号有其用途。例如,如果替换正斜杠/,可以使用gsub("/","") 而不是gsub(/\//,"")
    【解决方案3】:

    试试这个:

    awk '{gsub("include(\'"'"'./", "include\('"'"'", $0); print > FILENAME}' *.php
    

    你放错了反斜杠

    或者这个:

     awk '{gsub("include(\'./", "include(\'", $0); print > FILENAME}' *.php
    

    这个怎么样?

    awk '{gsub("include(\47./", "include(\47", $0); print > FILENAME}' *.php
    

    你有没有尝试过而没有逃避任何事情

    awk '{gsub("include('./", "include('", $0); print > FILENAME}' *.php
    

    【讨论】:

    • 不工作这些错误被裁剪... awk: 警告: 转义序列 `\'' 被视为普通 `'' awk: 警告: 转义序列 `(' 被视为普通 `(' awk: ( FILENAME=xyz.php FNR=1) 致命:不匹配 ( 或 (: /include('.//
    • @GeekTantra 我没有控制台或安装 awk .. 我会在上面测试这些示例 ..
    • 那是因为 awk 正在写回文件作为它的处理同时。 !
    【解决方案4】:

    如果您只想这样做,则无需使用awk。 :) 另外,在读取文件的同时写入文件会导致数据丢失或损坏,尽量不要这样做。

    for file in *.php ; do
    # or, to do this to all php files recursively:
    # find . -name '*.php' | while read file ; do
      # make backup copy; do not overwrite backup if backup already exists
      test -f $file.orig || cp -p $file $file.orig
      # awk '{... print > NEWFILE}' NEWFILE="$file" "$file.orig"
      sed -e "s:include('\./:include(':g" "$file.orig" >"$file"
    done
    

    只是为了澄清数据丢失方面:当awk(或sed)开始处理文件并且您要求他们读取第一行时,他们实际上将执行缓冲读取,即他们将从文件系统(让我们简化并说“来自磁盘”)一个与其内部读取缓冲区一样大的数据块(例如 4-65KB),以便获得更好的性能(通过减少磁盘 I/O)。假设你的文件重新工作大于缓冲区大小。进一步的读取将继续来自缓冲区,直到缓冲区耗尽,此时第二个数据块将从磁盘加载到缓冲区等。

    但是,在您读取第一行之后,即在第一块数据从磁盘读取到缓冲区之后,您的 awk 脚本会打开输入文件本身 FILENAME,用于写入 截断,即磁盘上的文件大小重置为 0。此时,您原始文件的所有剩余部分都是awk 内存中的前几千字节数据。 Awk 将愉快地继续从内存缓冲区中逐行读取并产生输出,直到缓冲区耗尽,此时awk 可能会停止并为您留下一个 4-65k 的文件。

    附带说明,如果您实际上使用 awk 来扩展(例如 print "PREFIX: " $0),而不是收缩(gsub(/.../, ""))数据,那么您几乎肯定会以无响应的 awk 和一个不断增长的文件。 :)

    【讨论】:

    • sed, awk, 两者都能胜任。
    • 可以说少了一级引用/转义。 :) 但真正不可原谅的部分,无论使用哪个(awk 或 sed),本质上是在读取第一行后截断每个 PHP 文件,即如果文件大于 awk/sed 的读取缓冲区,他只是将文件截断为很多字节。
    • awk 实际上为我完成了这项工作。这与使用 sed 或 awk 无关,而是关于哪个更舒服。
    • 正确,awk 或 sed 都可以。不过,我确实希望您的文件都不大于 65k。 :) 只是为了好玩,获取或制作一个 100K 的文件并运行原始的 gawk { ... print > FILENAME } file 命令。我的awk 在 68k 处持平。哎呀。 :)
    • 那是因为它写回了 gawk 当前正在处理的文件。它与cat file > file 的概念相同。提供不同的文件名(并在需要时将其重命名为原始文件名)是可行的方法。
    猜你喜欢
    • 1970-01-01
    • 2017-04-09
    • 2014-03-24
    • 2015-06-05
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    • 2017-12-29
    • 1970-01-01
    相关资源
    最近更新 更多