Випадково використано переадресацію виходу> замість труби |


21

Місяць тому я написав сценарій Python, щоб зіставити MAC та IP адреси від stdin. І два дні тому я згадав це і використовував для фільтрування виводу, tcpdumpале він пішов не так через помилку друку. Я набрав

tcpdump -ne > ./mac_ip.py

а вихід - нічого. Але вихід повинен бути "Невідомим", якщо він не може проаналізувати вхід, тому я зробив cat ./mac_ip.pyі знайшов усі tcpdumpдані замість програми. Тоді я зрозумів, що мені слід користуватися

tcpdump -ne | ./mac_ip.py

Чи є спосіб повернути свою програму? У будь-якому разі я можу написати свою програму ще раз, але якщо це повториться з більш важливою програмою, я мав би змогу щось зробити. АЛЕ Є якийсь спосіб сказати перенаправлення виводу, щоб перевірити файл і попередити, чи він виконується?


18
Ви можете повернути свою програму з останньої резервної копії перед перезапис, інакше ні. BTW в оболонці ви можете вказати, set -o noglobberі bash більше не буде перенаправляти в існуючі файли. Детальніше дивіться тут: cyberciti.biz/tips/howto-keep-file-safe-from-overwriting.html
eckes

12
У вас не повинно бути дозволу на написання важливих виконуваних файлів ...
Хаген фон Ейтцен

20
@eckesset -o noclobber
GnP

38
@HagenvonEitzen Я ненавиджу подібну пораду, як ніби ви встановили належне право власності та дозволи на кожен одноразовий скрипт оболонки та python, який ви коли-небудь писали, перш ніж запустити його (і, звичайно, знову коротко, якщо вам доведеться редагувати його ). Це лише незначно важливіше, ніж "Ви не повинні вводити текст, >коли маєте на увазі |". Не забувайте реальність.
Джейсон C

30
Git repos дешеві. Зробіть весь свій код, незалежно від того, наскільки малий і безглуздий, а потім така помилка - це швидке та просте виправлення.
Кейсі

Відповіді:


22

На жаль, я підозрюю, що вам потрібно буде це переписати. (Якщо у вас є резервні копії, настав час їх вийти. Якщо ні, я б настійно рекомендував би встановити режим резервного копіювання на майбутнє. Багато варіантів, але для цієї відповіді немає теми.)

Я вважаю, що розміщення виконуваних файлів в окремому каталозі та додавання цього каталогу до програми PATHє корисним. Таким чином, мені не потрібно посилатися на виконувані файли явним шляхом. Мій уподобаний каталог програм для особистих (приватних) скриптів є "$HOME"/binі його можна додати до шляху пошуку програми за допомогою PATH="$HOME/bin:$PATH". Зазвичай це буде додано до сценаріїв запуску оболонки .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призначений для специфічних для хоста речей (на відміну від каталогу, який спільно використовується між хостами через мережеве кріплення), і може бути або не може бути записаний некористувальними користувачами.
чепнер

4
@gardenhead, звичайно, це одне стандартне місце. Я використовую /use/local/binдля локально встановлених сценаріїв і програм, які, ймовірно, будуть використовуватися в декількох облікових записах користувачів, і $HOME/binдля речей, особистих для одного користувача. В обох є цінність.
roaima

1
Зауважте, що Fedora, схоже, намагається натиснути на використання$HOME/.local/bin
Зай Лінкс

1
@Zan eeeww! Хоча серйозно, дякую. Схоже, RH намагається підштовхнути все, ~/.localтому що це ще один предмет, переміщений зі свого "традиційного" місця.
roaima

38

Щоб запобігти перезапису існуючих файлів перенаправленням, >скористайтеся noclobberопцією в bashабо будь-якій оболонці, схожій на POSIX (також (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) Очевидно, що резервні копії є істотними, ніхто не радив ОП не робити резервних копій, ця відповідь ні в якому разі не передбачає створення резервних копій, а резервні копії редактора припускають, що ви редагували файл у редакторі. 3) Знову ж, ви думаєте лише про код, який написав ОП, як у цьому конкретному прикладі, але питання та ця відповідь застосовні до будь-якого файлу на машині, включаючи системні файли.
тердон

8

Я настійно раджу мати важливі сценарії під git repo , синхронізованими дистанційно (як це зробить фантастична самоорганізована платформа ), як йдеться у коментарі @ casey.

Таким чином ви захищені від поганих людських помилок, таких як повернення файлу до попереднього робочого стану та виконання його заново.


4

Чи можна відновити файл?

Коротка відповідь: Не зазвичай.

@Mark Plotnick вказує у коментарях, ви можете відновити .pyфайли за .pycдопомогою Uncompyle . Це має бути ідеально підходить для вашої ситуації.

Взагалі, однак, це набагато складніше. Теоретично ви можете використовувати інструменти криміналістики для відновлення файлів. Напевно, найпростішим я користувався 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віддалений хост Unix, до якого ви маєте sshдоступ. (Використовуйте, ssh-copy-idщоб вас не запитали пароль повторно.)

  5. Використовуйте git. Існує багато чудових навчальних посібників з початку роботи. Спробуйте man gittutorial, man gittutorial-2і man giteveryday. Налаштування власного сховища git не є складним, але ви також можете безкоштовно і безкоштовно створити віддалене сховище на github.com

  6. Якщо вищезазначені рішення мають занадто велику вагу, ви можете зберегти невеликі сценарії на gist.github.com . Хоча можна вставити або завантажити з веб-браузера, я рекомендую використовувати інтерфейс суті командного рядка, щоб зробити речі дуже простими.

Я рішуче перешкоджаю використанню "noclobber".

Так, якщо ви вирішите, ви можете зробити це, set -o noclobberщоб ви отримували повідомлення про помилки, коли намагаєтесь перезаписати наявний файл. На мою думку, це погана ідея. *

Це змушує оболонку працювати нестандартним способом, не маючи видимих ​​ознак, чи включена вона. Ви повинні використовувати інший синтаксис, щоб робити звичайні речі. Найгірше, якщо ви звикнете до noclobber, то одного дня ви будете користуватися іншим автоматом Unix без noclobber, і така аварія може повторитися.

Як ви, напевно, знаєте, оболонка Unix була розроблена як гострий інструмент для експертів. Він швидкий у використанні і не зашкодить вам - і він скоротить вас, якщо ви забудете, який кінець - точковий. Але, чим більше ти його використовуєш, тим більше, я думаю, ти оціниш, що це може бути хорошою справою.


* Зноска: можливо, прийміть мою думку із зерном солі. Я також та людина, яка вважає, що велосипедні тренажери - це погана ідея.


Я також деякий час викладав Unix. Багато моїх студентів ніколи не навчилися цінувати пряму простоту Unix; Я кажу їм, що вони не самотні, і, принаймні, все ще можуть вчитися під час спілкування над посібником Unix Hater's Guide, який відображає частину мінного поля для них. simson.net/ref/ugh.pdf
Джейсон

Також: Я згоден - тренувальні колеса на велосипеді корисні для тих, хто навчиться їздити на триколісному велосипеді.
Джейсон

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

Ви не вказали, чи працюєте ви на ПК чи сервері. Якщо ваші файли зберігаються на спеціалізованому файловому сервері, часто існують автоматичні резервні копії ("знімки"), які зберігаються на апаратному забезпеченні файлового сервера (ОС на).

Під 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

Це було сказано раніше, і я повторю це ще раз. Використовуйте систему контролю ревізії.

Резервні копії призначені для відновлення несправності обладнання. Контроль редагування призначений для таких ситуацій, як у вас (і він має багато інших цілей). Засоби контролю версій дозволяють зберігати історію файлу та повертатися до будь-якої точки цієї історії.

Приклади інструментів контролю версій включають підрив (SVN) (трохи вже старий, але все ще хороший), меркуріальний (hg) та git (git) (важкий у використанні). svn хороший для офісних документів, а інші um-mergables, git і hg перевершили його для більшості інших ролей. hg і git дозволяють вам працювати в режимі офлайн та синхронізуватись із віддаленим сервером для розповсюдження та резервного копіювання.

Прочитайте про контроль редагування, потім розподіліть контроль редагування, а потім спробуйте їх.


Я погоджуюсь, що використання контролю версій найкраще для таких ситуацій, як моя, але надання прав на права файлів не менш важливо
Bharath Teja
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.