【问题标题】:Sed not working with Linux when deleting string from text file [duplicate]从文本文件中删除字符串时,Sed 无法与 Linux 一起使用 [重复]
【发布时间】:2017-04-13 23:38:39
【问题描述】:

上一个主题 - https://stackoverflow.com/questions/40808975/overwrite-script-in-bash-shell

我正在从事一个大学项目,我们必须创建一个带有删除和恢复选项的回收站。我已经完成了这两个部分并且恢复选项工作(大部分)。它将已删除文件的位置保存在名为 FilePaths 的 txt 文件中,以在将文件恢复到其原始位置时用作参考。

我知道当一个文件位置的副本保存到这个文件中时会导致问题,所以我必须在 bash 脚本中创建一行,从文本文件中删除特定的文件位置字符串。

我知道 sed 可以提供帮助,我可以操纵它来做任何我想做的事情,但问题是它似乎根本没有做任何事情。我什至用一个简单的“test2”文本文件对它进行了测试,里面有 hello 这个词。

sed '/hello/d' test2

这绝对没有任何作用。我已经用双引号试过了,但仍然没有,它根本没有从我的 test2 文件中删除“hello”

就恢复功能而言,这是我目前所拥有的

#!/bin/sh
#navigate to the Recycle_Bin directory
cd $HOME/Recycle_Bin

#take the string from FilePaths and save it to restore
restore="$(grep "$1" "$HOME/FilePaths")"

#take the string saved in restore and use it as the file's path
filename="$(basename "$restore")"

#remove the string matching restore within FilePaths
sed '/$restore/d' $Home/FilePaths

#set location
location="$(readlink -f "$location")"

#move file to original location
mv -i "$1" "$(grep "$1" "$HOME/FilePaths")"

谁能想到 sed 不起作用的任何原因?我一直在寻找几个小时,但找不到任何答案,我可以使用 awk 但我觉得 sed 会使我的代码更简单

【问题讨论】:

  • 你真的检查过sed '/hello/d' test2 的输出吗?它是否仍然包含带有hello 的行(输出,而不是文件)?如果有,你可以试试echo "hello" | sed '/hello/d' 吗?它应该什么也不输出。
  • 至少,正如 JNevill 的回答所评论的那样,一个简单的解决方法是,您应该在引用 sed 变量的 sed 命令周围使用双引号,否则它不会被扩展。
  • 所以我把它写成sed -i "/"$restore"/d" $HOME/FilePaths
  • 这里引用太多了,就sed -i "/$restore/d" $HOME/FilePaths。双引号和单引号共享一些效果(它们将其内容标记为单个字段),但双引号要求 shell 检查字符串并在适当时扩展其内容,而单引号仅包含从 shell 角度来看的文本
  • 当你确认你没有很好的/.../ 命令时,有两个选项可供你使用:要么在将$restore 变量中的每个/ 转义,然后将其传递给@ 987654334@,或者在sed 中使用另一个分隔符,你肯定不会在你的$restore 变量中找到它(尽管/.../ 是常态,可以使用任何分隔符:我经常使用+...+ 或@ 987654339@ 当我处理很多/)

标签: linux bash sed


【解决方案1】:

感谢大家的帮助,尤其是 Aaron 和 JNevill,他们在回答这个问题时提供了很大帮助。

我可以使用这段代码来完成这项工作

sed -i "s+$restore++g" $Home/FilePaths

除了使用 + 分隔符之外,还可以使用其他符号,最明显的是 @ 以防 + 符号在字符串的文件路径中使用。

我还将这条线从 location 属性的上方移到了最底部。这意味着在 location 属性中使用了位置后,它被删除了

我的完整代码

#!/bin/sh
#navigate to the Recycle_Bin directory
cd $HOME/Recycle_Bin

#take the string from FilePaths and save it to restore
restore="$(grep "$1" "$HOME/FilePaths")"

#take the string saved in restore and use it as the file's path
filename="$(basename "$restore")"

#set location
location="$(readlink -f "$location")"

#move file to original location
mv -i "$1" "$(grep "$1" "$HOME/FilePaths")"

#remove the string matching restore within FilePaths
sed -i "s+$restore++g" $Home/FilePaths

希望对你有帮助

【讨论】:

  • 感谢您添加答案。要将其标记为已解决,您会单击最有用的解决方案旁边的刻度线吗?如果您愿意,您可以接受自己的,尽管将其授予他人通常是一种善意。
  • 您最终将面临的一个问题是,您选择作为 sed 表达式分隔符的任何字符,例如示例中的 +,作为文件或目录名称中的字符都是合法的。如果我删除文件/var/tmp/this+that.txt/var/tmp/dir+name/file.txt 会怎样?
  • 在这种情况下,我将添加一个解释此分隔符选择的部分
【解决方案2】:

由于您的路径可能包含/,您可能必须使用另一个标记:

试一试

sed -e "\|$restore|d" -i $Home/FilePaths

sed -e "\@$restore@d" -i $Home/FilePaths

(感谢 Jonathan Leffler comment)。

【讨论】:

  • 是的,你必须使用另一个标记;这不是选择标记的 POSIX 方式。它在 GNU sed 中工作吗? POSIX 需要"\|$restore|d",其中反斜杠表示这是以下一个字符作为分隔符的搜索。
  • 感谢@JonathanLeffler 我已经使用s||| 命令进行了测试,但不是作为地址 ... -不,如果没有反斜杠`\`,这将无法工作GNU sed.
【解决方案3】:

您的sed 命令不会在任何地方写入结果,因此它默认为标准输出。您应该使用-i 标志来编辑文件。

sed -i "/$restore/d" $Home/FilePaths

如果这仍然给您带来问题,您可以使用:

sed -i "s/$restore//g" $Home/FilePaths

如果$restore 是文件中该行的全部内容,它将执行相同的操作。

【讨论】:

  • 我的理解是/<term>/d 将删除包含<term> 的整行(我可能错了,因为我通常只是s/<term>//g。这是s/<term>//g 的不同行为感觉就像OP的意图。两者的行为不同,但如果<term>是唯一在行中找到的东西,那么这两个命令将具有相同的结果。
  • 没错,我上一条评论错了。我赞成你的答案和另一个答案,因为两者都有部分解决 OP 的问题:使用 -i 修改文件,使用双引号来扩展文本,并注意它不会t 产生任何不需要的sed 分隔符/标记。
  • 请注意,如果$restore 包含它正在恢复的文件名的任何斜杠,这将遇到麻烦。
猜你喜欢
  • 2018-11-27
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
  • 2023-03-21
  • 1970-01-01
  • 2018-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多