bash/sed/awk: 替换任意文件中的任意子串
bash/sed/awk: replace arbitrary substring in arbitrary files
更新:
我试过 markp-fuso 的回答,效果很好
我开始感到沮丧,因为我不是 bash/sed 之类的日常用户。
起点:
我有很多包含很多源文件的子文件夹 (.c,.cpp,.cxx
)。
这些源文件在工程文件(.vcxproj
).
中被引用编译
我想做的事情:
我想查找所有包含字符串 #import
的源文件。然后我想找到所有引用这些源文件的项目文件。
然后我想编辑这些项目文件中所有出现的这些引用
例如<Include="folder/file.cpp"/>
-> <Include="folder/file.cpp" Attribute="Value"/>
我试过的:
egrep -lir --include=*.{c,cpp,cxx} "(#import)" ./e3 | xargs -L 1 basename | egrep -ir --include=*.vcxproj -f - ./e3 | sed 's/:/ /g'
生成这样的列表:
./src/base/base.vcxproj <ClCompile Include="Folder1\Folder1File1.cpp" />
./src/mod/mod.vcxproj <ClCompile Include="Folder2\Folder2File1.cpp" />
./src/ext/ext.vcxproj <ClCompile Include="Folder3\Folder3File1.cpp" />
于是我尝试了
egrep -lir --include=*.{c,cpp,cxx} "(#import)" ./e3 | xargs -L 1 basename | egrep -ir --include=*.vcxproj -f - ./e3 | sed 's/:/ /g' | awk '{ sed -iE 's/(,)/ Attribute="Value"/g' }'
哪些错误出
bash: syntax error near unexpected token `('
我已经尝试过使用 shell 脚本的解决方案,但也没有用,我不知道是否以及如何解决上述错误消息。我对任何解决方案都持开放态度,只要它是 bash 内的 运行,甚至可以比我想出的更严重。
设置:
mkdir -p src/{base,mod,ext}
echo 'some stuff on this line
<ClCompile Include="Folder1\Folder1File1.cpp" />
some more stuff on this line' > src/base/base.vcxproj
echo 'some stuff on this line
<ClCompile Include="Folder2\Folder2File1.cpp" />
some more stuff on this line' > src/mod/mod.vcxproj
echo 'some stuff on this line
<ClCompile Include="Folder3\Folder3File1.cpp" />
some more stuff on this line' > src/ext/ext.vcxproj
为了让某些东西在我的环境中工作,我将中间数据放在本地文件中:
$ cat proj.dat
./src/base/base.vcxproj <ClCompile Include="Folder1\Folder1File1.cpp" />
./src/mod/mod.vcxproj <ClCompile Include="Folder2\Folder2File1.cpp" />
./src/ext/ext.vcxproj <ClCompile Include="Folder3\Folder3File1.cpp" />
一个使用参数替换的想法:
while read -r fname oldstring # 2nd-Nth space-delimited fields go into the single variable "oldstring"
do
oldstring="${oldstring//\/\\}" # escape literal backslashes
newstring="${oldstring//\/>/ Attribute=\"Value\"\/>}" # replace /> with Attribute="Value"/>
echo "##################### ${fname}"
sed "s|${oldstring}|${newstring}|g" "${fname}"
done < proj.dat
备注:
- sed 替换应用于文件中的所有事件
- 如果其他数据集导致
sed
因错误而中止,则可能需要添加其他参数扩展以转义其他有问题的字符
- 在
Attribute
字符串的前面添加了一个 space,因为文本描述表明 />
之前可能不存在 space(例如,...file.cpp"/>
)
- OP 应该能够将当前
egrep | xargs | egrep | sed
传送到此 while
循环(将 done < proj.dat
替换为 done
)
- 一旦 OP 对结果感到满意,可以将
-i
标志添加到 sed
调用以执行 ${fname}
的就地更新
生成:
##################### ./src/base/base.vcxproj
some stuff on this line
<ClCompile Include="Folder1\Folder1File1.cpp" Attribute="Value"/>
some more stuff on this line
##################### ./src/mod/mod.vcxproj
some stuff on this line
<ClCompile Include="Folder2\Folder2File1.cpp" Attribute="Value"/>
some more stuff on this line
##################### ./src/ext/ext.vcxproj
some stuff on this line
<ClCompile Include="Folder3\Folder3File1.cpp" Attribute="Value"/>
some more stuff on this line
更新:
我试过 markp-fuso 的回答,效果很好
我开始感到沮丧,因为我不是 bash/sed 之类的日常用户。
起点:
我有很多包含很多源文件的子文件夹 (.c,.cpp,.cxx
)。
这些源文件在工程文件(.vcxproj
).
我想做的事情:
我想查找所有包含字符串 #import
的源文件。然后我想找到所有引用这些源文件的项目文件。
然后我想编辑这些项目文件中所有出现的这些引用
例如<Include="folder/file.cpp"/>
-> <Include="folder/file.cpp" Attribute="Value"/>
我试过的:
egrep -lir --include=*.{c,cpp,cxx} "(#import)" ./e3 | xargs -L 1 basename | egrep -ir --include=*.vcxproj -f - ./e3 | sed 's/:/ /g'
生成这样的列表:
./src/base/base.vcxproj <ClCompile Include="Folder1\Folder1File1.cpp" />
./src/mod/mod.vcxproj <ClCompile Include="Folder2\Folder2File1.cpp" />
./src/ext/ext.vcxproj <ClCompile Include="Folder3\Folder3File1.cpp" />
于是我尝试了
egrep -lir --include=*.{c,cpp,cxx} "(#import)" ./e3 | xargs -L 1 basename | egrep -ir --include=*.vcxproj -f - ./e3 | sed 's/:/ /g' | awk '{ sed -iE 's/(,)/ Attribute="Value"/g' }'
哪些错误出
bash: syntax error near unexpected token `('
我已经尝试过使用 shell 脚本的解决方案,但也没有用,我不知道是否以及如何解决上述错误消息。我对任何解决方案都持开放态度,只要它是 bash 内的 运行,甚至可以比我想出的更严重。
设置:
mkdir -p src/{base,mod,ext}
echo 'some stuff on this line
<ClCompile Include="Folder1\Folder1File1.cpp" />
some more stuff on this line' > src/base/base.vcxproj
echo 'some stuff on this line
<ClCompile Include="Folder2\Folder2File1.cpp" />
some more stuff on this line' > src/mod/mod.vcxproj
echo 'some stuff on this line
<ClCompile Include="Folder3\Folder3File1.cpp" />
some more stuff on this line' > src/ext/ext.vcxproj
为了让某些东西在我的环境中工作,我将中间数据放在本地文件中:
$ cat proj.dat
./src/base/base.vcxproj <ClCompile Include="Folder1\Folder1File1.cpp" />
./src/mod/mod.vcxproj <ClCompile Include="Folder2\Folder2File1.cpp" />
./src/ext/ext.vcxproj <ClCompile Include="Folder3\Folder3File1.cpp" />
一个使用参数替换的想法:
while read -r fname oldstring # 2nd-Nth space-delimited fields go into the single variable "oldstring"
do
oldstring="${oldstring//\/\\}" # escape literal backslashes
newstring="${oldstring//\/>/ Attribute=\"Value\"\/>}" # replace /> with Attribute="Value"/>
echo "##################### ${fname}"
sed "s|${oldstring}|${newstring}|g" "${fname}"
done < proj.dat
备注:
- sed 替换应用于文件中的所有事件
- 如果其他数据集导致
sed
因错误而中止,则可能需要添加其他参数扩展以转义其他有问题的字符 - 在
Attribute
字符串的前面添加了一个 space,因为文本描述表明/>
之前可能不存在 space(例如,...file.cpp"/>
) - OP 应该能够将当前
egrep | xargs | egrep | sed
传送到此while
循环(将done < proj.dat
替换为done
) - 一旦 OP 对结果感到满意,可以将
-i
标志添加到sed
调用以执行${fname}
的就地更新
生成:
##################### ./src/base/base.vcxproj
some stuff on this line
<ClCompile Include="Folder1\Folder1File1.cpp" Attribute="Value"/>
some more stuff on this line
##################### ./src/mod/mod.vcxproj
some stuff on this line
<ClCompile Include="Folder2\Folder2File1.cpp" Attribute="Value"/>
some more stuff on this line
##################### ./src/ext/ext.vcxproj
some stuff on this line
<ClCompile Include="Folder3\Folder3File1.cpp" Attribute="Value"/>
some more stuff on this line