意外使用了输出重定向>而不是管道|


21

一个月前,我写了一个Python脚本来映射来自stdin的MAC和IP地址。两天前,我记得它并曾经过滤过输出,tcpdump但由于输入错误而出错。我打过

tcpdump -ne > ./mac_ip.py

输出什么也没有。但是,如果无法解析输入,则输出应为“未知”,因此我cat ./mac_ip.py找到了所有tcpdump数据而不是程序。然后我意识到我应该使用

tcpdump -ne | ./mac_ip.py

有什么办法可以让我的程序恢复原状吗?无论如何,我都可以再次编写程序,但是如果在更重要的程序中再次发生该程序,我应该可以做一些事情。或有什么办法告诉输出重定向以检查文件并警告它是否是可执行文件?


18
您可以在覆盖之前从上次备份取回程序,否则不能这样做。您可以在shell中指定BTW,set -o noglobberbash不会再重定向到现有文件中。详情请参阅此处:cyberciti.biz/tips/howto-keep-file-safe-from-overwriting.html
eckes

12
您不应该对重要的可执行文件具有写权限...
Hagen von Eitzen

20
@eckesset -o noclobber
GnP

38
@HagenvonEitzen我讨厌这样的建议,好像您在运行它之前曾经编写的每个一次性shell和python脚本上都设置了适当的所有权和权限一样(当然,如果您必须对其进行编辑,请简短地再次返回) )。它仅比“您不应该在输入>时输入”更有意义|。不要忘记现实。
杰森C

30
Git回购很便宜。提交所有代码,无论它们多么小而毫无意义,然后这样的错误都是快速简便的修复。
Casey

Answers:


22

可悲的是,我怀疑您需要重写它。(如果有备份,那么现在就可以使用它们了。如果没有,我强烈建议您为将来建立一个备份机制。有很多可用的选项,但是此答案不在主题之内。)

我发现将可执行文件放在单独的目录中,并将该目录添加到PATH会很有帮助。这样,我不需要通过显式路径引用可执行文件。我的个人(私人)脚本首选程序目录为"$HOME"/bin,可以使用将其添加到程序搜索路径PATH="$HOME/bin:$PATH"。通常会将其添加到Shell启动脚本.bash_profile和/或中.bashrc

最后,没有什么能阻止您删除自己对所有可执行程序的写许可权:

touch some_executable.py
chmod a+x,a-w some_executable.py    # chmod 555, if you prefer

ls -l some_executable.py
-r-xr-xr-x+ 1 roaima roaima 0 Jun 25 18:33 some_executable.py

echo "The hunting of the Snark" > ./some_executable.py
-bash: ./some_executable.py: Permission denied

2
/usr/local/bin是用户创建的可执行文件和脚本的标准位置
gardenhead

4
@gardenhead这取决于系统的设置方式。/usr/local用于特定于主机的事物(与通过网络安装在主机之间共享的目录相对),并且非root用户可能可以写或不能写。
chepner

4
@gardenhead当然是一个标准位置。我/use/local/bin用于可能由多个用户帐户使用的本地安装的脚本和程序,以及$HOME/bin用于单个用户的个人化东西。两者都有价值。
roaima

1
请注意,Fedora似乎正在尝试使用$HOME/.local/bin
Zan Lynx

1
@Zan eeeww!严重的是,谢谢。似乎RH试图将所有东西都推入,~/.local因为那是从其“传统”位置移走的又一个项目。
roaima

38

要防止现有文件被重定向覆盖,请在中或任何类似POSIX的外壳程序中>使用该noclobber选项bash(也可以在(t)csh功能的实际来源中使用该选项,尽管您可以set noclobber使用set -o noclobber/ 代替set -C)。然后,如果您需要强制替换文件,请使用>|重定向操作符(>!中的(t)csh)。

例:

$ echo abc > file
$ set -o noclobber
$ echo xyz > file
bash: file: cannot overwrite existing file
$ echo xyz >| file
$ cat file
xyz

顺便说一句,您可以使用来检查当前设置set -o

$ set -o
...
monitor         on
noclobber       on
noexec          off
...

尽管这完美地回答了这个问题,但我不建议这样做。1.键入>||不是键入的可能性要比键入的可能性小得多>。2.进行备份非常容易并且非常明智(值得称赞的编辑器可以保存最新版本;还有cron,等等)。3.每段代码都应置于版本控制之下,即使是很小的脚本也应置于此之下。YMMV。
maaartinus

2
@maaartinus加油,1)输入两个单独的字符而不是一个字符显然不太可能。2)显然,备份是必不可少的,没有人建议OP不要进行备份,这个答案绝不意味着没有备份,而编辑器备份则假设您已经在编辑器中编辑了文件。3)同样,您仅在考虑OP编写的代码,如在此特定示例中一样,但是问题和答案适用于计算机上的任何文件,包括系统可执行文件。
terdon

8

我强烈建议将重要的脚本放在git repo下,并进行远程同步(一个漂亮的自托管平台可以做到),就像@casey的评论所说。

这样,您就可以避免人为错误,例如将文件还原到先前的工作状态并再次执行。


4

文件可以恢复吗?

简短答案:通常不行。

@Mark Plotnick在注释中指出,您可以使用Uncompyle恢复.py文件。这应该适合您的情况。.pyc

但总的来说,这要困难得多。从理论上讲,您可以使用取证工具来取消删除文件。我使用过的最简单的大概是testdisk(又名“ PhotoRec”)。它仅在某些时候有效,并且过程缓慢。通常这是不值得的,因此,是的,这是可能的,但真正的答案是“否”。

可以>改为不重写可执行文件?

否。没有标准的方法告诉外壳程序不要仅对标记为可执行文件的文件进行重定向。有一个“ noclobber”,它将阻止重定向到现有文件(无论是否可执行),但请参阅下面的我的评论。

将来要做什么?

  1. 这听起来可能很愚蠢,但是为了防止将来出现错误,您可能不需要执行任何操作。我敢打赌,您已经学到了这一课。

    我使用和教Unix很长时间了,尽管人们经常犯一次这个错误,但很少重复。为什么不?出于同样的原因,一个有刀经验的人不会割伤自己:人类善于学习。最终,做正确的事情成为第二天性。

  2. 使用文本编辑器为您进行备份。例如,如果使用emacs,则程序的先前版本将保存在mac_ip.py〜中。可以将其他编辑器配置为类似工作(例如,中的“设置备份” .nanorc)。对于不支持自动备份的编辑器,可以在.bashrc中进行简单化的功能:

    myeditor() { cp -p "$1" "$1~";  editor "$1"; }
    
  3. 使自己轻松制作副本。例如,在您正在处理的项目的目录中,可能有一个Makefile,其目标是这样的:

    # Use `make tar` to backup all files in this directory.
    # Tar filename will be ../<currentdirectory>-<date>.tar.gz 
    DIRNAME = $(shell basename `pwd`)
    TIMESTAMP = $(shell date +%s)
    tar:
        @echo "[Tarring up ${DIRNAME}.tar.gz]"
        (cd .. ; tar -zcvf "${DIRNAME}-${TIMESTAMP}.tar.gz" "${DIRNAME}")
    

    (注意:stackexchange将上面的TAB误渲染为4个空格。)

  4. 同样,您可以创建一个Makefile目标,该目标rsync对您有权ssh访问的远程Unix主机执行操作。(使用,ssh-copy-id这样就不会再次要求您输入密码。)

  5. 使用git。关于入门,有很多很棒的教程。尝试man gittutorialman gittutorial-2man giteveryday。设置自己的git存储库并不难,但是您也可以在github.com上免费创建一个远程存储库

  6. 如果上述解决方案太繁重,则可以将小脚本保存到gist.github.com。虽然可以从Web浏览器粘贴或上传,但我建议使用命令行要点界面使事情变得非常简单。

我强烈不鼓励使用“ noclobber”。

是的,如果您选择这样做,可以set -o noclobber在尝试覆盖现有文件时收到错误消息。我认为这是一个坏主意。*

它使外壳以非标准的方式工作,没有可见的指示是否启用了外壳。您必须使用其他语法来完成正常的工作。最糟糕的是,如果您习惯了noclobber,那么有一天您将使用另一台没有noclobber的Unix机器,这种情况可能会再次发生。

您可能知道,Unix Shell被设计为专家的敏锐工具。它使用起来很快,不会妨碍您-如果您忘记了哪一点是尖锐的,它将使您受益匪浅。但是,使用得越多,我就越会体会到这是一件好事。


*脚注:也许我的观点有些含糊。我也是那种认为自行车辅助轮是个坏主意的人。


我也有一段时间教Unix。我的许多学生从未学过欣赏Unix的直接简单性。我告诉他们,他们并不孤单,并且至少在向Unix Hater手册致以同情的同时仍然可以学习,该手册为他们绘制了一些雷区。 simson.net/ref/ugh.pdf
Jason

另外:我同意-自行车脚轮对任何学习如何骑三轮车的人都有帮助。
杰森

2

如果您最近查看或编辑了脚本并且仍在内存缓冲区中,那么您可能能够在首次出现数据后对其进行恢复。否则,您几乎不走运。

如果您通过管道输送到tee写入一个文件中(以及STDOUT),而不是>(或tee -a代替>>),那么你可以很容易地更换tee有一个别名,函数,或符号链接到一个脚本,警告说,如果他们将要写入文件的用户到可执行。

以下内容绝非理想之举,可以进行很多改进,但这只是一个起点,作为一个可能的示例:

wee.sh:

#!/bin/bash

if [ -n "${2}" ]; then
  if [ "$(ls -l "${2}" | awk '{print $1}' | grep x)" ]; then
    echo executable
  else
    tee -a "${2}"
  fi
elif [ "$(ls -l "${1}" | awk '{print $1}' | grep x)" ]; then
  echo executable
else
  tee "${1}"
fi

...然后只是echo 'alias tee="/path/to/wee.sh"' >> ~/.bashrc类似的东西。

从好的方面来说,至少您会获得更多练习,并且Python脚本的第二个版本可能比第一个版本好得多!


1

您没有指定是在PC还是服务器上工作。如果您的文件恰好存储在专用文件服务器上,则文件服务器硬件(上的OS)通常会保留自动备份(“快照”)。

在Linux下

虚拟的隐藏快照目录存在于文件系统的每个目录中。

尝试:

cd .snapshot   
ls -l

如果该目录存在,那么您可能很幸运。您应该看到一系列目录,其中包含在特定时间点自动存储的备份。名称表示快照存储在过去的相对时间。例如:

hourly.0
hourly.1
hourly.2
hourly.3
hourly.4
hourly.5
nightly.0
nightly.1
nightly.2
nightly.3
nightly.4
nightly.5
nightly.6
weekly.0
weekly.1
weekly.2

进入足够旧的任何时间点目录(在文件覆盖错误之前)。在时间点目录中,您应该看到过去该时间点的../..目录(和所有子目录)的状态。

cd nightly.6
ls  # look around   
tee < mac_ip.py  # check for the correct content
cp mac_ip.py ~/safekeeping/mac_ip.py  # save the old file

笔记:

  1. ls -a 不会显示 .snapshot目录;您必须明确命名。它实际上是由文件服务器插入的。它在文件系统中不存在为真实目录。
  2. 这些自动快照是滚动的历史记录。最终,旧的变更最终将消失,并丢失。您意识到需要回文件后,需要尽快使用此技术。

在Windows下

隐藏的快照目录可以命名为〜snapshot,并且仅存在于给定驱动器的根目录下。

忠告

快照是一个安全网络,可在大多数时间(而不是每次)使用。我同意其他建议,git即使对于琐碎的文件也应使用版本控制系统(例如)。


1

之前已经说过,我再说一遍。使用修订控制系统。

备份用于恢复硬件故障。修订控制适用于您这样的情况(它还有许多其他用途)。版本控制工具使您可以保留文件的历史记录,并返回到该历史记录中的任何位置。

版本控制工具的示例包括Subversion(SVN)(现在有点旧了,但仍然不错),Mercurial(hg)和git(git)(难以使用)。svn适用于Office文档,其他可合并的商品git和hg在大多数其他角色中都超过了它。hg和git允许您脱机工作并与远程服务器同步,以进行分发和备份。

阅读修订控制,然后分发修订控制,然后尝试。


我同意使用修订控制最适合我的情况,但是授予文件正确的权限也同样重要
Bharath Teja
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.