Чи можу я змусити `cut` змінити файл на місці?


Відповіді:


14

Ви не можете. Або використовуйте ed або GNU sed або perl, або робіть те, що вони роблять за кадром, це створити новий файл для вмісту.

ed, портативний:

ed foo <<EOF
1,$s/^\([^,]*\),\([^,]*\),\([^,]*\).*/\1,\3/
w
q
EOF

GNU sed:

sed -i -e 's/^\([^,]*\),\([^,]*\),\([^,]*\).*/\1,\3/' foo

Perl:

perl -i -l -F, -pae 'print @F[1,3]' foo

cut, створивши новий файл (рекомендується, оскільки якщо ваш сценарій буде перервано, ви можете просто запустити його знову):

cut -d , -f 1,3 <foo >foo.new &&
mv -f foo.new foo

cut, замінюючи файл на місці (зберігає право власності та дозволи foo, але потребує захисту від перебоїв):

cp -f foo foo.old &&
cut -d , -f 1,3 <foo.old >foo &&
rm foo.old

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


Краще, ніж .oldметод змін на місці,echo "$(cut -d , -f 1,3 <foo)" > foo
GypsyCosmonaut

1
@GypsyCosmonaut Ні, це не "краще". Це більш крихке. Єдина його перевага полягає в тому, що вона коротша за тип. Основна проблема вашого методу полягає в тому, що якщо помилка трапиться під час обробки вхідного файлу або запису виводу, дані втрачаються. Він також не працює з бінарними даними: вихід буде усічений у першому нульовому байті. Навіть з текстовими файлами він видаляє порожні рядки з кінця файлу. З великими файлами він може вийти з ладу, оскільки дані повинні зберігатися як рядок у пам'яті оболонки (і пам’ятайте, якщо це трапляється, дані втрачаються).
Жил "ТАК - перестань бути злим"

oO Спасибі, я не знав, що можуть виникнути проблеми з нульовим байтом
GypsyCosmonaut

Я думаю, що це простіше:cut -d , -f 1,3 foo > foo.new rm foo mv foo.new foo
LoMaPh

@LoMaPh Дійсно, я не знаю, чому я перейменував старий файл: він не має жодних переваг перед перейменуванням нового файлу. Це також простіше, тому що крок вам не потрібен rm foo. І не варто дзвонити rm foo, бо mv foo.new fooатомний: він видаляє стару версію і одночасно ставить нову версію.
Жил "ТАК - перестань бути злим"

23

Пакет moreutils від ubuntu (а також debian ) має програму під назвою sponge, яка також вирішує вашу проблему.

Від чоловічої губки:

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

Що дозволить вам зробити щось на кшталт:

cut -d <delim> -f <fields> somefile | sponge somefile

9

Я не думаю, що це можливо cutсамостійно. Я не зміг його знайти на сторінці "людина" чи "Інформація". Можна зробити щось таке, як

mytemp=$(mktemp) && cut -d" " -f1 file > $mytemp && mv $mytemp file

mktempробить вас відносно безпечним тимчасовим файлом, в який ви можете cutпередавати вихід.


1

Спробуйте vim-way:

$ ex -s +'%!cut -c 1-10' -cxa file.txt

Це дозволить редагувати файл на місці (так спершу зробіть резервну копію).

Як альтернативи використовують grep, sedабо gawk.



0

Ну, оскільки cutотримує менше результатів, ніж читає, ви можете:

cut -c1 < file 1<> file

Тобто, зробіть його stdin fileвідкритим у режимі лише для читання, а його stdout - fileвідкритим у режимі читання + запису без укорочення ( <>).

Таким чином, cutбуде просто перезаписати файл над собою. Однак він залишить решту файлів недоторканими. Наприклад, якщо він fileмістить:

foo
bar

Вихід стане:

f
b
bar

f\nb\nЗамінили foo\n, але barвсе ж є. Вам потрібно буде обрізати файл після cutйого закінчення.

З ksh93, ви можете зробити це з його <>;оператором, який діє як, <>за винятком випадків, якщо команда успішна, ftruncate()викликається в дескрипторі файлів. Так:

cut -c1 < file 1<>; file

З іншими оболонками вам потрібно буде скористатися ftruncate()іншими засобами, такими як:

{ cut -c1 < file; perl -e 'truncate STDOUT, tell STDOUT';} 1<> file

хоча звернення perlлише до цього трохи непосильне, особливо враховуючи, що perlце легко виконати таку cutроботу, як:

perl -pi -e '$_ = substr($_, 0, 1)' file

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

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