2

我有一段 C/C++ 源代码,其中 #include 语句中的文件名与 *.h 文件不完全匹配。匹配正确,但不区分大小写。这是在 Windows 系统中出现的源文件类型。

我想更改所有源文件,以便所有#include语句都与它们引用的文件名完全匹配。

所有要更改的文件名都用引号引起来。

例子:

文件列表

File1.h
FILE2.H
file1.cpp

文件1.cpp

#include "file1.h"
#include "file2.h"

将 file1.cpp 更改为

#include "File1.h"
#include "FILE2.H"

我想创建一个自动脚本来执行此更新。

我在下面列出了这个过程的各个步骤,但我似乎无法将这些部分组合在一起。

  1. 创建所有 *.h 文件的列表,ls *.h > include.lst. 这将创建一个包含正确大小写的所有文件名的文件。
  2. 使用文件名include.lst创建一个 sed 命令's/<filename>/<filename>/I',该命令执行不区分大小写的搜索并用正确大小写的文件名替换匹配项。我相信我只需更换一次,但添加全局 g 将处理多次发生。
  3. 将此替换列表应用于目录中的所有文件。

我想要关于如何创建 sed 命令 2) 给定的建议include.lst。我想我可以处理剩下的。

4

5 回答 5

2
for hfile in $(find /header/dir -type f -iname '*.h'); do
    sed -i 's/#include "'$hfile'"/#include "'$hfile'"/gI' file1.cpp
done

我希望我得到了正确的报价:)-i在申请之前尝试不使用。

您可以将调用包装sed在另一个循环中,如下所示:

for hfile in $(find /header/dir -type f -iname '*.h'); do
    for sfile in $(find /source/dir -type f -iname '*.cpp'); do
        sed -i 's/#include "'$hfile'"/#include "'$hfile'"/gI' "$sfile"
    done
done
于 2012-11-07T21:25:46.103 回答
2
  1. 在脚本中使用sed,或使用 Perl 脚本:

    find . -name *.c -print0 | xargs -0 sed -i.bak -e "s/\#include\s\"\([^\"]+/)\"/\#include\s\"\L\1\"/"
    

    -i.bak将文件备份到,original_file_name.bak所以如果你搞砸了,你不必担心

    此行将 C 文件中包含的所有标题更改为小写。

  2. Then you want to change all files names:

    find . -name *.h -print0 | xargs -0 rename 's/(*)/\L\1/'
    

    This renames all header file to lower case.

This is for linux only. If you are using Windows, you might want to use Perl or Python script for all above.

于 2012-11-07T21:56:08.550 回答
0

This might work for you (GNU sed):

sed 's|.*|s/^#include "&"$/#include "&"/i|' list_of_files | sed -i -f - *.{cpp,h} 
于 2012-11-07T23:55:04.197 回答
0

Thanks for all the details on lowercasing filenames and #include strings. However, my original question was to perform a literal replacement.

Below is the basic command and sed script that met my requirements.

ls *.h *.H | sed -e "s/\([^\r\n]*\)/s\/\\\(\\\#include\\\s\\\"\\\)\1\\\"\/\\\1\1\\\"\/gi/g" >> sedcmd.txt

  1. ls *.h *.H creates a list of files, one line at a time
  2. Pipe this list to sed.
  3. Search for the whole line, which is a filename. Put the whole line in group 1. s/\(^\r\n]*\)/
  4. Replace the whole line, the filename, with the string s/\(\#include\s"\)<filename>"/\1<filename>"/gi

The string #include<space>" is placed in group 1. The i in the gi states to do a case insensitive search. The g is the normal global search and replace.

Given a filename ACCESS.H and cancel.h, the output of the script is

s/\(\#include\s"\)ACCESS.H"/\1ACCESS.H"/gi
s/\(\#include\s"\)cancel.h"/\1cancel.h"/gi

Finally, the sed command file can be used with the command

sed -i.bak -f sedcmd.txt *.cpp *.h
于 2012-11-08T07:49:18.713 回答
0

My solution doesn't fail for pathnames containing slashes (hopefully you don't contain % signs in your header paths).

It's also orders of magnitude faster (takes ~13 seconds on a few hundred files, as opposed to several minutes of waiting).

#!/bin/bash

shopt -s globstar failglob nocaseglob

# You should pushd to your include path-root.
pushd include/path/root
headers=( **/*.h )
popd
headers+=( *.h )    # My codebase has some extra header files in the project root.

echo ${#headers[*]} headers

# Separate each replacement with ;
regex=""
for header in "${headers[@]}"; do
   regex+=';s%#include "'"$header"'"%#include "'"$header"'"%gI'
done
regex="${regex:1}"

find . -type f -iname '*.cpp' -print0 | \
    xargs -0 sed -i "$regex"

It's much faster to make sed run just once per file (with many ;-separated regexes).

于 2018-05-11T10:40:46.467 回答