Заміна файлу: команда overwrite

У команди sort є параметр-o для перезапису файлу:

$ sort file1  -o  file2

Ця запис еквівалентна наступній:

$ sort file1  &gtfile2

Якщо file1 і file2 – це один і той же файл, то перенаправлення> очистить вхідний файл, не виконуючи сортування А параметр-o працює коректно, т к вхідні дані сортуються і зберігаються в тимчасовому файлі до того, як створюється вихідний файл

Багато інші команди також могли б використовувати параметр-o

Наприклад, sed могла б редагувати файл прямо на місці:

$ sed s / UNIX / UNIX (TM) / g ch2-o ch2 Так не працює

Було б непрактично змінювати всі подібні команди так, щоб мож було додати цей параметр Більш того, це взагалі погана ідея: краще централізувати функції, як робить оболонка за допомогою оператора > Давайте напишемо програму overwrite, яка буде виконувати цю роботу Приклад, наведений вище, виглядатиме так:

$ sed  s/UNIX/UNIX(TM)/g  ch2 | overwrite ch2

Основна думка вельми невибаглива – просто зберігати вхідні дані, поки не буде досягнутий кінець файлу, потім скопіювати їх у вказаний файл:

# Overwrite: копіювати стандартний ввід в висновок після EOF

# Версія 1 З ПОМИЛКОЮ PATH = / bin :/ usr / bin

case  $# in

1)    ;

*)    echo Usage:  overwrite file  1&gt&amp2  exit 2 esac

new=/tmp/overwr$

trap rm  –f  $new exit 1  1 2 15

cat> $ new # зібрати вхідні дані

cp $ new $ 1 # перезаписати вхідний файл rm-f $ new

Команда cp використана замість mv для того, щоб права і власник вихідного файлу (якщо він вже існував) не змінилися

У цій заманливо простої версії зроблена фатальна помилка: якщо під час виконання cp користувач натисне клавішу Del, То вихідний вхідний файл буде зіпсований Необхідно запобігти зупинці перезапису вхідного файлу, що спричинюється перериванням:

# Overwrite: копіювати стандартний ввід в висновок після EOF

# Версія 2 І тут є ПОМИЛКА PATH = / bin :/ usr / bin

case  $# in

1)    ;

*)    echo Usage:  overwrite file  1&gt&amp2  exit 2 esac

new=/tmp/overwr1$ old=/tmp/overwr2$

trap rm  –f  $new $old exit 1 1 2 15

cat> $ new # отримати вхідні дані

cp $ 1 $ old # зберегти вихідний файл

trap’ 1 15 лютого # до завершення ігнорувати сигнали cp $ new $ 1 # перезаписати вхідний файл

rm –f  $new $old

Якщо клавіша Del  натиснута до початку обробки вихідного файлу, то тимчасові файли видаляються, і з файлом нічого не відбувається Після створення резервної копії сигнали ігноруються, тому остання команда cp не буде перервана і файл буде перезаписаний повністю

Все ще залишається невелика проблема Розглянемо

$ sed  s/UNIX/UNIX(TM)g precious | overwrite  precious

command  garbled: s/UNIX/UNIX(TM)g

$ ls -l precious

–rw–rw–rw–  1 you                    0 Oct    1 09:02  precious        #$%@*

$

Якщо в програмі, що постачає overwrite вхідними даними, є помилка, то її висновок буде порожнім, і надійна overwrite, як їй і належить, знищить дані у вхідному файлі

Можна запропонувати кілька рішень Наприклад, overwrite може запитувати підтвердження на заміну файлу, але якщо зробити цю команду інтерактивною, багато її переваги будуть втрачені Можна зробити так, щоб overwrite перевіряла свої вхідні дані на «непустоту» (за допомогою test-z), але це некрасиво і неправильно, до того ж якась частина вихідних даних вже може бути сгенерирована до моменту виявлення помилки

Кращим рішенням є запуск програми, яка генерує дані, під контролем overwrite – так, щоб можна було перевіряти код завершення Традиції і наша інтуїція виступають проти такого підходу У конвеєрі overwrite зазвичай знаходиться в кінці Але вона повинна бути першою, тому що інакше не працюватиме правильно Команда overwrite нічого не направляє в стандартний висновок, так що універсальність зберігається А її синтаксис не такий вже незвичайний: time, nice, nohup – всі ці команди сприймають інші команди в якості аргументів

Ось безпечна версія програми:

# Overwrite: копіювати стандартний ввід в висновок після EOF

# Остаточна версія

opath=$PATH PATH=/bin:/usr/bin

case  $# in

0|1)      echo Usage: overwrite file  cmd  [args] 1&gt&amp2 exit  2 esac

file= shift

new=/tmp/overwr1$  old=/tmp/overwr2$

trap rm-f $ new $ old exit 1 1 15 лютого # очистити файли

if PATH = $ opath $ @ > $ New # отримати вхідні дані then

else fi

cp $ file $ old # зберегти вихідний файл

trap’ 1 15 лютого # до завершення ігнорувати сигнали cp $ new $ file

echo &quotoverwrite:  failed, $file unchanged&quot  1&gt&amp2 exit 1

rm –f  $new $old

Вбудована в оболонку команда shift зрушує весь список аргументів на одну позицію вліво: $ 2 перетворюється в $ 1, $ 3 в $ 2 і т д Вираз

«$ @» Має на увазі всі аргументи (після виконання shift), як і $ *, але не інтерпретовані докладніше про це буде розказано в раз справі 57

Зверніть увагу, що PATH відновлюється для запуску команд користувача якби цього не відбувалося, то команди, що не містяться в / bin або / usr / bin, були б недоступні для overwrite

Тепер overwrite працює (хоч і виглядає дещо громіздко):

$ cat  notice

UNIX  is a Trademark  of  Bell  Laboratories

$ overwrite notice sed  s/UNIXUNIX(TM)/g  notice

command  garbled:  s/UNIXUNIX(TM)/g overwrite:  sed  failed, notice  unchanged

$ cat  notice

UNIX  is a Trademark  of  Bell  Laboratories                 Без змін

$ overwrite notice sed  s/UNIX/UNIX(TM)/g  notice

$ cat  notice

UNIX(TM)  is a Trademark of  Bell  Laboratories

$

Команда sed часто застосовується для того, щоб замінити всі входження слова іншим Маючи в наявності overwrite, легко створити командний файл, що автоматизує виконання даного завдання:

$ cat  replace

# Replace: замінити str1 в файлах на str2

PATH=/bin:/usr/bin case  $#  in

0|1|2)  echo Usage: replace str1  str2  files  1&gt&amp2  exit 1 esac

left=””  right=”

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*