Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在linux bash脚本中,使用tee随机更新文件失败_Linux_Bash_Ubuntu_Sed_Tee - Fatal编程技术网

在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次
有人能解释为什么会这样吗

这是一个功能齐全的脚本,您也可以在其中运行实验。(所有必需的文件都是由脚本生成的,因此您只需将其复制/粘贴到bashscriptfile中并运行即可)

问候
DonPromillo

问题在于,您正在使用
tee
覆盖
$filepath
,而
sed
正试图从中读取。如果
tee
先截断它,然后
sed
得到一个空文件,最后在另一端得到一个长度为
0
的文件

如果您有GNU
sed
,您可以使用
-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
的文件

如果您有GNU
sed
,您可以使用
-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”
我认为应该可以工作