Я знаю основы этих трех. И причина, по которой cat < file > file очищает содержимое файла. Но я не понимаю, почему cat < file >> file вместо того, чтобы записывать содержимое дважды, объединяет содержимое как в бесконечном цикле while.

2 ответа2

1

Ну, мой cat (в Kubuntu) говорит, что input file is output file и выходит. Я понимаю, что ваш cat не такой умный (или как ленивый).

То, что вы наблюдаете, довольно легко объяснить. cat читает и пишет кусками. Предположим, что первый блок не достигает конца файла (EOF), а его содержимое объединяется в конце того же файла. Чтение cat продвинулось на некоторое количество байтов, но конец файла "сместился" на ту же величину. По сути, cat снова так же далека от EOF, как и в начале. И это продолжается и продолжается и продолжается.

Как будто вы бежали, и на каждые 100 метров финишная черта была удалена еще на 100 метров от вас. Вы никогда не достигнете этого, и пройденное расстояние будет расти без конца.

Если исходное расстояние составляет 100 метров или меньше. В этом случае вы доберетесь до финиша до того, как он переместится. Аналогично, cat может закончить, если файл достаточно мал, но я действительно в этом сомневаюсь. Я ожидаю, что cat "знает", что она попала в EOF, только когда она пытается прочитать снова и может прочитать 0 байтов, не более. Это означает, что он уже читает до EOF на предыдущем шаге, когда он читает более 0 байтов. Но в вашем случае, если он прочитал больше 0 байтов на предыдущем шаге, то файл сразу же вырос после того, как все еще есть данные для чтения.

Я предсказываю два случая, чтобы ваша cat остановилась:

  • когда файл пуст (длиной 0 байт),
  • если файл не существует и вы измените порядок перенаправлений (например, cat >> file < file будет работать, cat < file >> file выдаст ошибку; это потому, что перенаправления "обслуживаются" слева направо, >> создает файл, если необходимо, < требует, чтобы файл существовал).

В общем случае использование одного и того же файла с перенаправлением stdin и stdout (или / и stderr) в одной команде вызывает проблемы. Тем не менее, если вам нужно сделать это, есть утилита sponge (например, в пакете moreutils для Ubuntu, Debian).

sponge читает стандартный ввод и записывает его в указанный файл. В отличие от перенаправления оболочки, губка впитывает весь свой ввод перед открытием выходного файла. Это позволяет сжимать конвейеры, которые читают и записывают в один и тот же файл.

Если выходной файл не указан, sponge выводит на стандартный вывод.

Вместо cat < file >> file запустите sponge < file >> file . Он будет делать то, что вы ожидали от cat (если, я думаю, файл не настолько велик, чтобы истощать ваши ресурсы, пока вы поглощены).

Другой способ - < file cat | cat >> file . Из-за буферизации между двумя cat s первый действительно ударит EOF и завершит работу, прежде чем второй расширит файл, если файл достаточно мал . Повторите эту команду несколько раз, начиная с небольшого (но не пустого) файла, и файл со временем станет достаточно большим, чтобы заставить команду вести себя как ваша оригинальная команда с одним cat . Примечание < file cat | unbuffer cat >> file избавляется от буфера и зацикливается даже для очень маленьких файлов.

0

Ну, в основном это работает следующим образом:

> используется для переопределения содержимого файла. Например: echo "HELLO WORLD" > file.txt .

>> используется для добавления содержимого в файл. Например: echo "New line" >> file.txt .

< вы можете использовать файл в качестве входных данных и перенаправить в другой файл. Например: cat < file.txt > file2.txt . Практическим примером является ftp myftpbox.com < commands.txt , он подключается к FTP и выполняет список команд, помещенный в файл commands.txt .

ПРИМЕЧАНИЕ: будьте осторожны при использовании > потому что вы можете переопределить существующий файл без какого-либо подтверждения, вы можете изменить это, запустив set -o noclobber .

Надеюсь, это поможет.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .