Це UUOC (марне використання кота) для перенаправлення одного файлу в інший?


36

Якщо я хочу, щоб зміст file2збігався зі змістом file1, я, очевидно, міг би просто запустити cp file1 file2.

Однак, якщо я хочу , щоб зберегти всі про file2 окрім Змісту-власника, права доступу, розширені атрибути, списки управління доступом, жорсткі посилання і т.д., і т.д., то я не хотів би працювати cp. * В цьому випадку я просто хочу , щоб грюкнути вмісту file1в file2.

Схоже, це зробить наступне:

< file1 > file2

Але це не працює. file2обрізається нічим і не пишеться. Однак,

cat < file1 > file2

справді працює.

Мене здивувало, що перша версія не працює.

Чи є друга версія UUOC? Чи є спосіб зробити це без виклику команди, лише використовуючи перенаправлення?

Примітка. Я усвідомлюю, що UUOC - це скоріше педантична точка, ніж справжня антидіаграма.

* Як виявив tniles09 , cp буде насправді робота в цьому випадку.


3
Чи < file1 > file2залежить те, що ви хочете, залежить від оболонок.
Майкл Гомер

13
Ну, це марне використання <...
jwodder

2
що таке анти-шаблон ?
mikeserv

6
@jwodder - це неправда. особливо коли ви говорите про копію. Подумайте, що відбувається, коли file1його немає, або ще не читається, і ви відкриваєте його до того, < як > буде відкрито вихід, а потім подумайте, що відбувається, коли ви дозволите catспробувати його відкрити.
mikeserv

3
@JonathanLeffler У zsh порожня команда з перенаправленнями викликає cat(за замовчуванням), по суті виконуючи другу команду. Більше про це див. У відповіді Стефана Шазеласа нижче, ніж у коментарі.
Майкл Гомер

Відповіді:


58

cat < file1 > file2не є УУПЦ. Класично <і >робити перенаправлення, які відповідають дублюванню дескрипторів файлів на системному рівні. Дублювання дескрипторів файлу самі по собі нічого не роблять (ну >перенаправлення відкриваються O_TRUNC, щоб бути точним, перенаправлення виводу робить усічення вихідного файлу). Не дозволяйте < >символам заплутати вас. Перенаправлення не переміщують дані - вони призначають дескриптори файлів іншим дескрипторам файлів.

У цьому випадку ви відкриєте file1та призначите цей дескриптор файлу дескриптору файлів 0( <file1== 0<file1) file2і призначите цей дескриптор файлу дескриптору файлу 1( >file2== 1>file2).

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


11
Можливо, це лише я, але моєю улюбленою частиною цієї відповіді є використання слова «лопата». :) Дуже ясно, дякую.
Wildcard

1
@Wildcard Я вважав за краще "перекачувати" над "лопатою", але все-таки гарне слово. +1
Мехрдад

чому лопата хороше слово?
bubakazouba

1
Одна лопата купу бруду, одна лопата повна, від однієї в іншу купу, як дані копіюються в буфер. Це хороша аналогія.
bsd

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

17

Це не так, оскільки, як зазначали інші, поведінка, про яку йдеться, залежить від оболонок. Як ви (ОП) вказали, це трохи педантично , можливо, навіть жартівливо? , сортування теми.

Однак, в системах GNU, ваша початкова передумова має інше доступне рішення: cp --no-preserve=all file1 file2. Спробуйте це, я думаю, це задовольнить описану вами ситуацію (наприклад, зміна вмісту file2, не змінюючи його атрибутів).

Приклад :

$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 16 Dec 16 12:21 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Lookout, world!
    Hello, world!
$ cp --no-preserve=all fred fezzik 
$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 14 Dec 16 12:22 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Hello, world!
    Hello, world!

ОНОВЛЕННЯ Насправді я щойно помітив, що мої системи cpсамі по собі, схоже, зберігають атрибути, якщо не вказано -aабо -pЯ використовую bash shell та GNU coreutils. Я думаю, ви дізнаєтесь щось нове щодня ...


Результати тестування (Wildcard), включаючи жорстке посилання та різні дозволи:

$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 file2
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the original contents of file2
$ cp file1 file2
$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 file2
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the contents of file1
$ 

Приємно. Я провів власний тест, включаючи жорстке посилання та різні дозволи, і, здається, ви прав.
Wildcard

Додано мої результати тестування; сподіваюся, ви не заперечуєте. :) Я не перевіряв ACL або розширені атрибути, але враховуючи, що число inode збережено, я на 99% впевнений, що це також було б.
Wildcard

Приємно ... зовсім не проти. :-)
tniles

13

У zsh, оболонці, де < file1 > file2працює, оболонка викликає cat.

У командному рядку, що складається лише з перенаправлень і не має команд, ані присвоєнь, zshвиклики $NULLCMD( catза замовчуванням), якщо єдиним перенаправленням не є <той, у якому випадку $READNULLCMD( pagerза замовчуванням) замість цього викликається. (це zshє випадком , коли він знаходиться в емуляції shабо в cshемуляції; в такому випадку він поводиться як оболонки, які він емулює).

Так:

< file1 > file2

насправді те саме, що

cat < file1 > file2

і

< file1

те саме, що

pager < file1

Для запису цей синтаксис не працює для ksh93
fpmurphy

8
< from > to

не працює, оскільки там немає команди; жодного процесу. Оболонка відкриває / створює файли та упорядковує перенаправлення (тобто дескриптори файлів, на які посилаються ці файли, розміщуються як 0 і 1: стандартний вхід і стандартний вихід). Але немає нічого, щоб виконати цикл для читання зі стандартного вводу та запису на стандартний вихід.

zshробить цю роботу, замінюючи налаштовану користувачем команду в цьому випадку "null command". Команда не видно у командному рядку, але вона все ще є. Для нього створений процес, і він працює так само. NULLCMDце catза замовчуванням, так що на < from > toнасправді означає cat < from > to , що в zsh, якщо NULLCMDне буде встановлено на що - то ще; це команда "неявна кішка".

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

Якщо catвиводиться із ситуації, наприклад, що інші команди можуть виконувати те саме завдання, це марно. Якщо він не знімний, то він не марний.

# useless, removable:
$ cat archive.tar | tar tf -    #  -->  tar tf archive.tar

# not removable (in POSIX shell):
$ cat > file
abc
[Ctrl-D]

# likewise:
STRING=$(cat file)

catЩо заменяемое це не те ж саме. Наприклад, замість цього cat > fileми можемо використовувати vi fileфайл для створення файлу. Це не вважається видаленням cat, використовуючи все, що залишилося для досягнення тієї ж задачі.

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

Деякі скриптові оболонки використовують, catоскільки вони думають, що це дозволяє їм перемістити вхідний операнд ближче до лівої частини командного рядка. Однак перенаправлення можуть бути в будь-якому місці командного рядка:

# If you're so inclined:
# move source archive operand to the left without cat:
$ < archive.tar tar xf - > listing

btw, вам не доведеться використовувати f -для дьогтю. tar xf -просто tar x.
ДНТ

@mikeserv Де йдеться про те, що catвін бере участь у створенні файлу? Відповідь чітко говорить, що оболонка це робить. Яку проблему > fileви маєте на увазі? Я часто використовую його поодинці для обрізання наявного файлу до нульової довжини або для забезпечення такого існування. Це питання стосується того, чому < from > toце не працює cat < from > to, і UUoC, а не "будь ласка, дайте мені причини, чому catце не є доброю заміною cp".
Каз

1
@dnt tar- це архіватор стрічки . Багато tarреалізацій за замовчуванням працюють із першим пристроєм на стрічці.
Стефан Шазелас

1

< file1 > file2 Здається, що оболонки залежать, на zsh це працює, на bash немає.

редагувати: видалено помилкове твердження


cp -aзберігає атрибути file1 та перезаписує атрибути file2. Навпроти бажаної поведінки. Крім того, я не можу сказати , навіть дивлячись на сторінці людини , що буде відбуватися з жорсткими посиланнями, але я думаю , що можна з упевненістю сказати , що file2 «s жорсткі посилання будуть НЕ будуть збережені.
Wildcard

Ви маєте рацію, я не прочитав питання досить уважно.
tastytea

1

На додаток до всіх хороших відповідей, ви можете уникнути UUOC шляхом імітаціїcat :

awk 1 file1 > file2   # For line-oriented text, not binaries.
dd if=file1 of=file2  # Works for binary files, too.
# many more geeky ways.

Ці команди не копіюють метадані файлу, як це cpбуло б просто .


Щоправда, але варто зазначити, що вони не мають переваги і мають лише недоліки (продуктивність, надійність) cat. Тут вам потрібна команда для переміщення даних між двома дескрипторами файлів і catє однією з найкращих для цього. Дивіться також, pvщо можна було б використовувати splice()в Linux для fifos (хоча це не так, fadvise(POSIX_FADV_SEQUENTIAL)як це робить GNU cat).
Стефан Шазелас

ddКоманда для бінарних файлів здається хорошою ... або буде catпрацювати так само добре для бінарних файлів?
Wildcard

@Wildcard catтакож працює для бінарних файлів (Unix, як правило, не розрізняє; проте деякі інструменти спеціально працюють по черзі, такі як awk, grep, wc, ... POSIX також визначає мінімальну найбільшу довжину рядка, так що теоретично інструмент, орієнтований на лінійку, може відмовитися мати справу з надмірно великими лініями.)
Єнс

2
@ StéphaneChazelas Ця відповідь також була задумана як язик у щоку. Схоже, незважаючи на сезон, у деяких людей є алергія на веселощі (не спрямовані на вас; я ціную ваш досвід роботи з оболонками та працюють норми Opengroup).
Єнс

sed '' < file1 > file2;-)
Цифрова травма

0

Якщо це працює, не виправляйте.

Я б користувався

cat < file1 > file2

і не потійте ПК семантики.

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