CCR
2024 年7 月 21 日 14:27
2
弱弱问一句,文本量很大,且必须用命令行吗,为何不用python呢……
我的话会直接招出来gedit……,然后文本自己转义(
另,可以看看pwsh,全平台通用,不过文本量大的话我还是推荐python
另附pwsh的部分你需要的函数
https://www.delftstack.com/zh/howto/powershell/replacing-strings-in-powershell
tiger
(小虎王)
2024 年7 月 21 日 14:31
3
您好,本次尝试使用豆包解决问题,分享链接为
提示词是这样构成的:
在bash脚本中,有三个变量 $oldContent,$newContent,$filePath
需要处理的问题是:将文件 $filePath 的内容中的 $oldContent 改为 $newContent
但是要注意点:
只可修改一次,不可 global replace
$oldContent,$newContent 的值是 HTML string,注意转义
如果不存在 $oldContent ,报错退出
取得的回答中,代码部分是:
#!/bin/bash
oldContent="$1"
newContent="$2"
filePath="$3"
if [! -f "$filePath" ]; then
echo "文件 $filePath 不存在"
exit 1
fi
content=$(< "$filePath")
if! echo "$content" | grep -q "$oldContent"; then
echo "未找到 $oldContent ,报错退出"
exit 1
fi
newContentEscaped=$(sed '/[\/&]/\\&/g' <<< "$newContent")
oldContentEscaped=$(sed '/[\/&]/\\&/g' <<< "$oldContent")
sed -i "0,/${oldContentEscaped}/s//${newContentEscaped}/" "$filePath"
原因很简单,这段代码不是给我用的,是给用户用的。
我的下面这个项目,安装插件需要修改入口文件。因为是入口,所以没有任何环境可以用。
我一直以来的做法是写 go 代码,然后编译。问题就是整个项目 10M+,这个文件占了 6M。
我现在想改成 install_windows.ps1
,install_linux.sh
。只用简单的 shell 实现。
调用 grep 和 sed 可以实现:
#!/bin/sh
FILEPATH="/usr/share/icons/"
OLD="usr"
NEW="bin"
echo $FILEPATH | grep $OLD #判断FILEPATH中是否包含OLD字符串,如果不包含,会返回1
if [ $? -eq 1 ]
then
echo "ERROR!"
return 1
else
TEMP=`echo $FILEPATH | sed "s/$OLD/$NEW/g"`
FILEPATH=`echo $TEMP`
fi
你好,感谢帮助。
代码不太行,原因是当 OLD、NEW 包含 斜杠、尖括号、反斜杠等等需要转义的内容是 sed "s/$OLD/$NEW/g"
会水土不服。
Unix下可以考虑用sed实现,诸如 sed -i 's/old/new/' filepath
,Windows下面用PowerShell可以用一些现成的dotNet的库,用 Get-Content 、-replace [regex]::Escape($oldContent), $newContent, 1、Set-Content等等组合一下可以做。
但要注意一个事情:如果文件很大,那么性能可能会很差,对sed这样的流处理的可能还好一点,pwsh下可能就不容乐观了。
至于转义,这个需要专门处理,没有命令行工具会主动帮你处理转义问题。当然还有一个奇技淫巧,那就是在脚本中先把文件里面需要转义的所有字符替换成特殊的不需要转义的字符,进行操作之后再替换回来,当然这个需要特定的条件,不具备普遍适用性。
1 个赞
感谢回答,其实我一开始的问题就是不知道 sed 参数该怎么转义。
我不想硬磕这个玩意,来论坛问问有没有其他好方法。既然没有,只能硬着头皮上了
网络上各种查,没查到,倒是看到了一句 escaping in bash is a nightmare
3_5105
2024 年7 月 21 日 16:43
10
go语言编译文件过大的话,考虑一下C或者C++?这种标准库应该完全够用
另外,此处是我给出的批处理示例,读取x.log的每一行,替换LABE字样为5105字样
@echo off
setlocal enabledelayedexpansion
set "filePath=x.log"
set "oldContent=LABE"
set "newContent=5105"
if exist "new_%filePath%" del /f/q "new_%filePath%"
set r=0
for /f "delims=" %%i in (%filePath%) do (
set v=%%i
echo !v:%oldContent%=%newContent%!>>new_%filePath%
if not "!v:%oldContent%=%newContent%!"=="!v!" set r=1
)
if %r%==0 echo 未找到需替换的字符串!
pause
Sonar
(Sonar)
2024 年7 月 21 日 16:59
11
借助 od 命令,将 $oldContent
、$newContent
、$filePath
转换为八进制后进行替换与对比,再使用 printf 命令将八进制转换为文本。
#!/bin/sh
filePath=$1
oldContent=$2
newContent=$3
oldContentOctal=$( printf '%s' "$oldContent" | od -An -to1 | tr -d '\n' )
newContentOctal=$( printf '%s' "$newContent" | od -An -to1 | tr -d '\n' )
oldFileOctal=$( od -An -to1 "$filePath" | tr -d '\n' )
newFileOctal=$( printf '%s' "$oldFileOctal" | sed "s/$oldContentOctal/$newContentOctal/" )
[ "$oldFileOctal" = "$newFileOctal" ] && exit 2
printf "$( printf '%s' "$newFileOctal" | tr ' ' '\\' )"
存在替换,退出码 $?
为 0
不存在替换,退出码 $?
为 2
我采用比较简单的方法 escape 了。这个方法需要将整个文件读进去。不过因为此文件也就几十 K,也就无所谓了。
escape() {
sed -E 's/[]\/$*.^|[]/\\&/g' <<<"$1"
}
escapedOldContent=$(escape "$oldContent")
escapedNewContent=$(escape "$newContent")
newContent=$(echo "$fileContent" | sed "s|$escapedOldContent|$escapedNewContent|")
Sonar
(Sonar)
2024 年7 月 28 日 15:15
13
提个建议哈,可以用 printf '%s' "$fileContent"
或者 echo -n "$fileContent"
,用 echo "$fileContent"
的话会在末尾加上一个额外的换行符
1 个赞