Это UUOC (бесполезное использование cat) для перенаправления одного файла в другой?


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это не UUOC. Классически, <и >делать перенаправления, которые соответствуют дублированию файловых дескрипторов на системном уровне. Дублирование файловых дескрипторов само по себе ничего не делает (ну, >перенаправления открываются 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 и 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 или расширенные атрибуты, но учитывая, что номер инода сохранен, я на 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делает эту работу, подставляя настраиваемую пользователем команду в этом случае «пустой команды». Команда не отображается в командной строке, но она все еще там. Для него создан процесс, и он работает так же. NULLCMDэто catпо умолчанию, так что на < from > toсамом деле означает cat < from > to , что в zsh, если NULLCMDне будет установлен на что - то еще; это команда «скрытого кота».

«Бесполезное использование cat» происходит, когда 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

Кстати, вам не нужно использовать f -для tar. 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 не будут сохранены.
Wildcard

Вы правы, я недостаточно внимательно прочитал вопрос.
вкусный чай

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 также определяет минимальную наибольшую длину строки, поэтому в теории инструмент, ориентированный на строки, может отказаться от работы с чрезмерно большими линиями.)
Jens

2
@ StéphaneChazelas Этот ответ также был задуман как насмешливый. Похоже, что, несмотря на сезон, некоторые люди испытывают аллергию на веселье (не направлено на вас; я ценю ваш опыт работы с оболочкой и работу над стандартами Opengroup).
Йенс

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

0

Если это работает, не исправляйте это.

я хотел бы использовать

cat < file1 > file2

и не парься на ПК от семантики.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.