在linux bash脚本中,使用tee随机更新文件失败
当使用在linux bash脚本中,使用tee随机更新文件失败,linux,bash,ubuntu,sed,tee,Linux,Bash,Ubuntu,Sed,Tee,当使用sed-e更新配置文件的某些参数并将其传输到|tee(将更新的内容写入文件)时,这会随机中断并导致文件无效(大小为0) 总之,此代码用于更新参数: # based on the provided linenumber, add some comments, add the new value, delete old line sed -e "$lineNr a # comments" -e "$lineNr a $newValue" -e "$lineNr d" $myFile | su
sed-e
更新配置文件的某些参数并将其传输到|tee
(将更新的内容写入文件)时,这会随机中断并导致文件无效(大小为0)
总之,此代码用于更新参数:
# based on the provided linenumber, add some comments, add the new value, delete old line
sed -e "$lineNr a # comments" -e "$lineNr a $newValue" -e "$lineNr d" $myFile | sudo tee $myFile
我设置了一个脚本,它调用这个更新命令100次
- 在与OSX共享目录的UbuntuVM(并行桌面)中 行为最多发生50次
- 在Ubuntu虚拟机(并行桌面)上 Ubuntu分区此行为最多发生40次
- 在本机系统(带有Ubuntu的IntelNUC)上,这种行为最多发生15次
DonPromillo问题在于,您正在使用
tee
覆盖$filepath
,而sed
正试图从中读取。如果tee
先截断它,然后sed
得到一个空文件,最后在另一端得到一个长度为0
的文件
如果您有GNUsed
,您可以使用-i
标志让sed
修改文件(其他版本支持-i
但需要参数)。如果您的sed
不支持它,您可以让它写入临时文件并将其移回原始名称,如
tmpname=$(mktemp)
sed -e "$lineToReplace a # $(date '+%Y-%m-%d %H:%M:%S'): replaced: $oldValue with: $newValue" -e "$lineToReplace a $newValue" -e "$lineToReplace d" "$filePath" > "$tmpname"
sudo mv "$tmpname" "$filePath"
或者,如果您想保留原始权限,可以这样做
sudo sh -c "cat '$tmpname' > '$filePath'"
rm "$tmpname"
或者使用您的tee
方法,如
sudo tee "$filePath" >/dev/null <"$tmpname"
rm "$tmpname"
sudo-tee“$filePath”>/dev/null问题在于,您正在使用tee
覆盖$filePath
,而sed
正试图从中读取。如果tee
先截断它,然后sed
得到一个空文件,最后在另一端得到一个长度为0
的文件
如果您有GNUsed
,您可以使用-i
标志让sed
修改文件(其他版本支持-i
但需要参数)。如果您的sed
不支持它,您可以让它写入临时文件并将其移回原始名称,如
tmpname=$(mktemp)
sed -e "$lineToReplace a # $(date '+%Y-%m-%d %H:%M:%S'): replaced: $oldValue with: $newValue" -e "$lineToReplace a $newValue" -e "$lineToReplace d" "$filePath" > "$tmpname"
sudo mv "$tmpname" "$filePath"
或者,如果您想保留原始权限,可以这样做
sudo sh -c "cat '$tmpname' > '$filePath'"
rm "$tmpname"
或者使用您的tee
方法,如
sudo tee "$filePath" >/dev/null <"$tmpname"
rm "$tmpname"
sudo-tee“$filePath”>/dev/null如果要扔掉stdout
,为什么要为此使用tee
?另外,由于您使用tee
覆盖文件的时间与使用sed
处理文件的时间完全相同,因此您很可能存在争用情况。如果tee
在sed
可以获取文件之前截断该文件,您将获得一个0
长度的文件。如果您的sed
支持它,您可以让它修改文件,否则您应该将输出写入临时文件,然后将其移动到原始名称管道的两侧是异步的;您不能保证sed
在tee
覆盖它之前完全消耗了myFile
的内容。感谢@EricRenouf和@chepner非常清楚地指出这一点。我之所以使用tee
主要是出于对管道的好奇。如果你扔掉stdout
,为什么要使用tee
?另外,由于您使用tee
覆盖文件的时间与使用sed
处理文件的时间完全相同,因此您很可能存在争用情况。如果tee
在sed
可以获取文件之前截断该文件,您将获得一个0
长度的文件。如果您的sed
支持它,您可以让它修改文件,否则您应该将输出写入临时文件,然后将其移动到原始名称管道的两侧是异步的;您不能保证sed
在tee
覆盖它之前完全消耗了myFile
的内容。感谢@EricRenouf和@chepner非常清楚地指出这一点。我之所以使用tee
基本上是出于对管道的好奇。我假设将sed
输出写入变量(而不是临时文件)也是可以接受的。@DonPromillo只要您小心如何将其返回到文件,printf'%s'$contents'>“$filePath”
应该可以工作我想我假设将sed
输出写入一个变量(而不是临时文件)也是可以接受的。@DonPromillo只要你小心如何将它返回到文件,printf“%s'$contents”>“$filePath”
我认为应该可以工作