Поменять строки в файле местами

Обновлено: 04.07.2024

Я хотел бы изменить порядок строк в текстовом файле (или stdin), сохранив содержимое каждой строки.

Итак, т. е., начиная с:

Я хотел бы закончить с

существует ли стандартная утилита командной строки UNIX для этого?

ссылки: FreeBSD, NetBSD, OpenBSD и OS X руководство страниц.

также стоит упомянуть: tac (ГМ, обратный cat ). Часть coreutils.

листать один файл в другой

(объяснение: добавить не начальную строку для хранения буфера, линии подкачки и буфера, распечатать строку в конце)

альтернативно (с более быстрым выполнением) от awk One-liners:

Если вы не можете вспомнить, что,

в системе с утилитами GNU другие ответы проще, но не весь мир GNU/Linux.

Если вам случится быть в vim использовать

попробовать tac , который работает в Linux, и если это не работает, используйте tail -r , который работает на BSD и OSX.

попробуйте выполнить следующую команду:

Просто Bash :) (4.0+)

самый простой метод использует

Мне очень нравится " хвост-r" ответ, но мой любимый ответ gawk.

в конце вашей команды put: | tac

редактировать ниже генерируется случайно отсортированный список чисел от 1 до 10:

где точки заменяются фактической командой, которая меняет список

tac

python: использование [:: -1] в sys.как stdin

для решения cross OS (т. е. OSX, Linux), которое может использовать tac внутри сценария оболочки используйте homebrew, как упоминалось выше, а затем просто псевдоним tac так:

Это будет работать как на BSD, так и на GNU.

У меня был тот же вопрос, но я также хотел, чтобы первая строка (заголовок), чтобы остаться на вершине. Поэтому мне нужно было использовать силу awk

PS также работает в cygwin или gitbash

вы можете сделать это с помощью vim stdin и stdout . Вы также можете использовать ex на POSIX-совместимой. vim это просто визуальный режим для ex . На самом деле, вы можете использовать ex С vim -e или vim -E (улучшенное ex mode). vim полезен, потому что в отличие от таких инструментов, как sed это буферизует файл для редактирования, в то время как sed используется для потоков. Возможно, вы сможете использовать awk , но вам придется вручную буферизировать все в переменная.

идея в том, чтобы сделать следующее:

  1. читать из stdin
  2. для каждой строки переместите ее в строку 1 (для обратного хода). Команда g/^/m0 . Это означает глобально, для каждой строки g ; соответствует началу строки, которая соответствует чему-либо ^ ; переместите его после адреса 0, который является строкой 1 m0 .
  3. печатать все. Команда %p . Это означает для диапазона всех линий % ; печать строки p .
  4. принудительно выйти без сохранения файла. Команда q! . Это означает, что хватит q ; сильн ! .

как сделать это многоразовые

я использую скрипт, который я называю ved (редактор vim, как sed ) использовать vim для редактирования stdin . Добавьте это в файл ved в своем пути:

я использую один вместо +'%p' +'q!' , потому что vim ограничивает вас до 10 команд. Поэтому слияние их позволяет "$@" иметь 9 + команды вместо 8.

Есть ли способ сделать это быстро с помощью сочетаний клавиш?

Вы можете рассмотреть возможность использования другого редактора, если вы не знакомы с vim. Вы можете настроить редактор для git только с помощью любого git config --global core.editor <whatever> или сразу для многих (включая git), включив export EDITOR=<whatever> в свой .bashrc .

Чтобы заменить текущую строку на следующую, введите ddp в командном режиме.

  • dd - удалить строку (в других редакторах она называется вырезать) и сохранить в регистре
  • p - вставить строку из регистра
Переместите курсор на первую строку, затем введите ddp . Если вы еще не находитесь в командном режиме, нажмите, Esc чтобы перейти в командный режим. dd удаляет текущую строку после копирования в "регистр". p копирует («помещает») содержимое регистра в ваш буфер после текущей строки. Точно так же вы можете поменять местами два символа с помощью xp или два слова с помощью dwwP . @KeithThompson, к сожалению, не так просто поменять местами два слова. @CS Вы имеете в виду тот факт, что dwwP это не работает одинаково, если два слова находятся в конце строки? (И поменять местами последнее слово в одной строке на первое слово в следующей строке еще сложнее.) @KeithThompson, да, хотя я почувствовал себя немного плохо после своего комментария, потому что это буквальный крайний случай;)

dd удаляет текущую строку, затем вы можете вставить удаленную строку с помощью p . Однако есть другой способ использования m . С помощью m вы можете перемещать строки, т.е.

:m 1 переместит текущую строку после строки 1

:m 0 переместит текущую строку наверх

:m $ переместит текущую строку вниз

В вашем примере поместите курсор в первую строку и введите :m $

Это ответ, который я также искал, чтобы расширить свои знания о vim. Благодарность! Это ответ, который я искал. Это может стать еще удобнее при одновременном проведении нескольких строк в визуальном режиме.

Несмотря на то , что вопрос довольно старый и помечено как ответили, я хотел бы расширить ответ, говоря , что вы можете использовать обычные команды режима, которые были предоставлены Sven Marnach с nnoremap примерно так:

Здесь мы добавляем "a перед удалением и вставкой команды для сохранения нашей строки в @a регистре, поэтому ваш регистр копирования по умолчанию не будет перезаписан. Однако он может перезаписать содержимое @a регистра (кто знает, но вы можете использовать его для чего-то важного в вашем случае использования, но этот шаг немного параноидален, вы можете пропустить его, если хотите), давайте исправим и это:

Теперь у нас есть два сопоставления, которые позволяют нам перемещать строки в файле с помощью сочетаний клавиш. Вы можете переопределить кнопки, я использую Alt + j / k , который был бы <A-j> и <A-k> для этих команд. Однако не все эмуляторы терминала поддерживают сопоставление клавиш Alt AFAIK.

Как я могу найти и заменить определенные слова в текстовом файле, используя командную строку?

  • sed = Stream EDitor
  • -i = на месте (т.е. сохранить обратно в исходный файл)
  • s = команда замены
  • original = регулярное выражение, описывающее слово для замены (или только само слово)
  • new = текст для замены
  • g = глобальный (т.е. заменить все, а не только первое вхождение)

file.txt = имя файла

@Akiva Если вы включите регулярные выражения, специальные символы в вашем поиске sed будут соответствовать им. Добавьте -r флаг, если вы хотите использовать вместо этого расширенные RE. @mcExchange Если / вам требуется сопоставить именно символ, вы можете просто использовать какой-то другой символ в качестве разделителя (например 's_old/text_new/text_g' ). В противном случае вы можете поставить \ перед любым из них, $ * . [ \ ^ чтобы получить буквальный символ. @BrianZ Для файловой системы вывод sed - это новый файл с тем же именем. Это одна из часто Команду OSX sed -i '.bak' 's/original/new/g' file.txt также можно запустить с расширением нулевой длины sed -i '' 's/original/new/g' file.txt , которое не будет создавать резервную копию. Пользователи MacOS должны будут добавить '' "после -i в качестве параметра для -i ed.gs/2016/01/26/os-x-sed-invalid-command-code, чтобы файл был перезаписан.

Есть несколько разных способов сделать это. Один использует sed и Regex. SED - это потоковый редактор для фильтрации и преобразования текста. Один пример выглядит следующим образом:

Другой способ , который может иметь больше смысла , чем < strin и > strout является с трубами!

обратите внимание, что cat в cat file | sed '. ' этом нет необходимости. Вы можете прямо сказать sed '. ' file . На самом деле это может быть уменьшено еще больше: sed -i'.bak' -e 's/unicorn/fox/g;s/hyper/brown/g' yarly будет принимать файл и делать 2 изменения на месте во время создания резервной копии. Использование time bash -c "$COMMAND" времени предполагает, что эта версия примерно в 5 раз быстрее.

Есть множество способов достичь этого. В зависимости от сложности того, чего можно достичь с помощью замены строки, и в зависимости от инструментов, с которыми пользователь знаком, некоторые методы могут быть предпочтительнее других.

В этом ответе я использую простой input.txt файл, который вы можете использовать для проверки всех примеров, представленных здесь. Содержимое файла:

Bash на самом деле не предназначен для обработки текста, но простые замены могут быть выполнены с помощью расширения параметров , в частности, здесь мы можем использовать простую структуру $ .

Этот небольшой скрипт не выполняет замену на месте, это означает, что вам придется сохранить новый текст в новый файл и избавиться от старого файла, или mv new.txt old.txt

Примечание: если вам интересно, почему while IFS= read -r ; do . done < input.txt он используется, то в основном это способ чтения файла строка за строкой. Смотрите это для справки.

AWK, будучи утилитой обработки текста, вполне подходит для такой задачи. Он может делать простые замены и намного более сложные, основанные на регулярных выражениях . Он обеспечивает две функции: sub() и gsub() . Первый из них заменяет только первое вхождение, а второй - заменяет вхождения во всей строке. Например, если у нас есть строка one potato two potato , это будет результат:

AWK может принять входной файл в качестве аргумента, поэтому input.txt было бы легко сделать то же самое с :

В зависимости от версии AWK, которая у вас есть, она может иметь или не иметь редактирование на месте, поэтому обычная практика - сохранять и заменять новый текст. Например что-то вроде этого:

Sed - это редактор строк. Он также использует регулярные выражения, но для простых замен достаточно сделать:

Что хорошо в этом инструменте, так это то, что он имеет редактирование на месте, которое вы можете включить с -i флагом.

Perl - это еще один инструмент, который часто используется для обработки текста, но это язык общего назначения, который используется в сетях, системном администрировании, настольных приложениях и во многих других местах. Он заимствовал много концепций / функций из других языков, таких как C, sed, awk и другие. Простую замену можно сделать так:

Как и у sed, у perl также есть флаг -i.

питон

Этот язык очень универсален и также используется в самых разных приложениях. Он имеет много функций для работы со строками, среди которых есть replace() , так что если у вас есть переменная, как var="Hello World" , вы могли бы сделать var.replace("Hello","Good Morning")

Простой способ прочитать файл и заменить строку в нем будет так:

Однако в Python вам также нужно выводить в новый файл, что вы также можете сделать из самого скрипта. Например, вот простой:

Этот скрипт должен вызываться input.txt как аргумент командной строки. Точная команда для запуска скрипта Python с аргументом командной строки будет

Конечно, убедитесь, что он ./myscript.py находится в вашем текущем рабочем каталоге, и, во-первых, убедитесь, что он установлен как исполняемый с chmod +x ./myscript.py

Python также может иметь регулярные выражения, в частности, есть re модуль, который имеет re.sub() функцию, которую можно использовать для более сложных замен.

Хорошая подборка! Другой возможный способ, не упомянутый здесь, - использование tr команды в Unix @TapajitDey Да, tr еще один замечательный инструмент, но учтите, что он предназначен для замены наборов символов (например, tr abc cde будет переводить a в c , b к d . Это немного отличается от замены целых слов как на sed или python

Вы можете использовать Vim в режиме Ex:

% выбрать все строки

g заменить все экземпляры в каждой строке

x написать, если изменения были внесены (есть) и выйти

Через команду gsub в awk,

Пример:

В приведенном выше примере все 1 заменяются на 0 независимо от столбца, в котором они расположены.

Если вы хотите сделать замену для определенного столбца, то сделайте так,

Пример:

Он заменяет 1 на 0 только в первом столбце.

Я использовал это на терминале MacOS, и он ничего не делал . Протестировано на Alpine Linux (в контейнере Docker) и не Я смотрю файл с inotifywait под sh окр, и представление данных в формате CSV (поскольку пользовательский формат глючит). Затем я подумал, что нет простого способа обработки CSV-документа в сценариях оболочки . И я хочу, чтобы он был очень легким. Поэтому я запустил довольно простой скрипт для разбора и отчета о CSV. Я прочитал спецификацию CSV и заметил, что она более сложна, чем я ожидал, и поддерживаю многострочное значение, заключенное в двойные кавычки. Я полагался на sed токенизацию, но вскоре понял, что даже то, что sed называется мультилиней, состоит из двух строк. Что тогда, если одно из моих значений CSV занимает более двух строк?

sed является s Tream ред itor , в том , что вы можете использовать | (трубы) для передачи стандартных потоков (STDIN и STDOUT в частности) путем sed и изменять их программно на лету, что делает его удобным инструментом в философии традиции Unix; но также можете редактировать файлы напрямую, используя -i параметр, указанный ниже.
Учтите следующее :

s/ используется для S ubstitute найденное выражение few с asd :

/g расшифровывается как «глобальный», что означает сделать это для всей строки. Если вы пропустите /g (с s/few/asd/ , всегда должно быть три слэша, несмотря ни на что) и few появятся дважды в одной строке, только первый few изменится на asd :

Немногие мужчины, немногие женщины, смелые.

Asd мужчины, немногие женщины, смелые.

Это полезно в некоторых обстоятельствах, таких как изменение специальных символов в начале строк (например, замена символов «больше», которые некоторые люди используют для цитирования предыдущего материала в темах электронной почты, на горизонтальной табуляции, оставляя после этого цитируемое алгебраическое неравенство позже в строке нетронутый), но в вашем примере, где вы указываете, что где-либо few происходит, его следует заменить, убедитесь, что у вас есть /g .

Следующие два параметра (флаги) объединены в один -ie :

-i Опция используется для редактирования я п установить на файл hello.txt .

-e Опция указывает на электронную XPression / команду для запуска, в данном случае s/ .

Примечание. Важно использовать его -i -e для поиска / замены. Если вы это сделаете -ie , вы создадите резервную копию каждого файла с добавленной буквой «е».

Я хотел бы изменить порядок строк в текстовом файле (или стандартный ввод), сохранив содержимое каждой строки.

Итак, т.е. начиная с:

Я хотел бы закончить с

Для этого есть стандартная утилита командной строки UNIX?

Важное примечание об изменении строк: сначала убедитесь, что в вашем файле есть завершающий символ новой строки . В противном случае последние две строки входного файла будут объединены в одну строку в выходном файле (по крайней мере, с использованием, perl -e 'print reverse <>' но, вероятно, это применимо и к другим методам).

Ссылка: страницы руководства FreeBSD , NetBSD , OpenBSD и OS X.

Просто помните, что опция -r не совместима с POSIX. Приведенные ниже решения sed и awk будут работать даже в самых сложных системах. Просто попробовал это на Ubuntu 12.04 и обнаружил, что для моей версии tail (8.13) нет опции -r. Вместо этого используйте «tac» (см. Ответ Михая ниже). Галочка должна переместиться ниже к tac. tail -r не работает в Ubuntu 12/13, Fedora 20, Suse 11.

tail: неверный параметр - r Попробуйте `tail --help 'для получения дополнительной информации. похож на свой новый вариант

В ответе, безусловно, должно быть упомянуто, что это только BSD, особенно потому, что OP запросил «стандартную утилиту UNIX». Это не в хвосте GNU, так что это даже не стандарт де-факто.

Также стоит упомянуть: tac (Гм, реверс cat ). Часть coreutils .

Перевернуть один файл в другой

Особенно стоит упомянуть тех, кто использует версию tail без опции -r! (У большинства пользователей Linux есть хвост GNU, у которого нет -r, поэтому у нас есть GNU tac). Просто примечание, потому что люди уже упоминали tac ранее, но tac, похоже, не установлен на OS X. Не то чтобы было сложно написать замену в Perl, но у меня нет реальной. Вы можете получить GNU TAC для OS X от Fink. Возможно, вы захотите также получить GNU tail, поскольку он делает некоторые вещи, которых нет у BSD tail. Если вы используете OS X с homebrew, вы можете установить tac с помощью brew install coreutils (устанавливается gtac по умолчанию). Одна из проблем заключается в том, что если в файле нет завершающей новой строки, первые две строки могут быть объединены в одну строку. echo -n "abc\ndee" > test; tac test ,

(Пояснение: добавьте не начальную строку для хранения буфера, измените строку и сохраните буфер, распечатайте строку в конце)

В качестве альтернативы (с более быстрым выполнением) из однострочников awk :

Если ты не можешь вспомнить это,

В системе с утилитами GNU другие ответы проще, но не во всем мире GNU / Linux .

Я желаю, чтобы это был принятый ответ. COS SED всегда в наличии, но не так tail -r и TAC. @ryenus: tac ожидается, что он будет обрабатывать произвольные большие файлы, которые не помещаются в памяти (хотя длина строки все еще ограничена). Неясно, sed работает ли решение для таких файлов. Точнее: код sed находится в O (n ^ 2) и может быть ОЧЕНЬ медленным для больших файлов. Отсюда и мое мнение об альтернативе awk, линейной. Я не пробовал вариант Perl, менее дружественный к трубам.

в конце вашей команды поставьте: | tac

tac делает именно то, что вы просите, он записывает каждый ФАЙЛ в стандартный вывод, в последнюю строку первым.

Так это противоположность кошки :-).

Почему он должен? Пожалуйста, объясните значение tac команды, это полезно для новых пользователей, которые могут закончить поиск по той же теме. Это действительно должен быть принятый ответ. Позор вышеупомянутому имеет так много голосов.

Если вы оказались в vim использовании

Я бы проголосовал, если бы вы кратко объяснили, что он сделал Да, я понял это, но я хотел разбить то, что делают различные части команды vim. Я сейчас посмотрел на ответ @kenorb связанный, который дает объяснение. g означает «сделать это глобально. ^ означает« начало строки ». m означает« переместить строку на новый номер строки ». 0 - на какую строку перейти. 0 означает «начало файла, перед текущей строкой 1». Итак: «Найдите каждую строку, у которой есть начало, и переместите ее в строку № 0.» Вы найдете строку 1 и переместите ее наверх. Ничего не делает. Затем найдите строку 2 и переместите ее выше строки 1 в начало файла. Теперь найдите строку 3 и переместите ее наверх. Повторите это для каждой строки. В конце вы заканчиваете, перемещая последнюю строку наверх. Когда вы закончите, вы перевернули все строки. Следует отметить, что глобальная команда: g ведет себя очень специфично по сравнению с простым использованием диапазонов. Например, команда «:% m0» не будет изменять порядок строк, в то время как «:% normal ddggP» (как и «: g / ^ / normal ddggP»). Хороший трюк и объяснение . О да, забыл жетон "см.

Попробуйте tac , который работает в Linux, и если это не работает, используйте tail -r , который работает в BSD и OSX.

@sage, к которому можно обратиться tail -r в случае, если tac он недоступен. tac не соответствует POSIX. Ни то, ни другое tail -r . Все еще не надежно, но это повышает шансы на то, что все работает. Я вижу - для случаев, когда вы не можете вручную / интерактивно изменить команду, когда она терпит неудачу. Достаточно хорошо для меня. Вам нужен надлежащий тест, чтобы увидеть, если TAC доступен. Что произойдет, если tac доступно, но не хватает оперативной памяти и поменять местами на полпути, потребляя гигантский поток ввода. Это терпит неудачу, и затем tail -r успешно обрабатывает остаток потока, давая неправильный результат. @PetrPeller См. Ответ выше комментария Роберта для OSX использовать homebrew. brew install coreutils и использовать gtac вместо tac и, если вы предпочитаете, добавить tac в качестве псевдонима, gtac если, например, вам нужен сценарий оболочки, который использовал его кросс-платформенный (Linux, OSX)

Попробуйте следующую команду:

вместо выражения gawk я бы сделал что-то вроде этого: sed 's/^5*://g' @GoodPerson, nl по умолчанию не будет нумерация пустых строк. -ba Опция доступна на некоторых системах, не не является универсальным (HP / UX приходит на ум, хотя я бы это не так) , тогда grep -n всегда будет номер каждой строки , которая соответствует (в данном случае пустой) регулярное выражение. Попробуйте это с файлом, содержащим строку, -nenenenenenene и посмотрите причину, по которой люди рекомендуют всегда использовать printf '%s\n' вместо echo . @mtraceur Я бы согласился с этим на этот раз, так как это общая функция.

Самый простой метод - это использование tac команду. tac является cat обратным. Пример:

Мне действительно нравится ответ " tail -r ", но мой любимый ответ gawk - .

Протестировано mawk на Ubuntu 14.04 LTS - работает, поэтому оно не является специфичным для GNU awk. +1

РЕДАКТИРОВАТЬ следующее генерирует случайным образом отсортированный список чисел от 1 до 10:

где точки заменены фактической командой, которая переворачивает список

нолики

Python: использование [:: - 1] на sys.stdin

Для кросс-ОС (то есть OSX, Linux) решение, которое может использовать tac внутри сценария оболочки, используйте homebrew, как уже упоминалось выше, тогда просто псевдоним tac выглядит так:

Для Linux Debian

Затем добавьте псевдоним

Это будет работать как на BSD, так и на GNU.

Если вы хотите изменить файл на месте, вы можете запустить

Это избавляет от необходимости создавать временный файл, а затем удалять или переименовывать оригинал и имеет тот же результат. Например:

На основании ответа от ephemient , который сделал почти, но не совсем то, что я хотел.

Со мной случается, что я хочу получить последние n строки очень большого текстового файла эффективно .

Первое, что я попробовал tail -n 10000000 file.txt > ans.txt , но я нашел это очень медленно, для tail приходится искать местоположение и затем возвращаться, чтобы напечатать результаты.

Когда я понимаю это, я переключаюсь на другое решение: tac file.txt | head -n 10000000 > ans.txt . На этот раз, позиция поиска просто должна переместиться с конца на желаемое место, и это экономит 50% времени !

Используйте, tac file.txt | head -n n если у вас tail нет -r опции.

Для пользователей Emacs: C-x h (выберите весь файл), а затем M-x reverse-region . Также работает только для выбора частей или линий и их возврата.

Я вижу много интересных идей. Но попробуй мою идею. Направьте ваш текст в это:

что предполагает, что символ '

' отсутствует в файле. Это должно работать на каждой оболочке UNIX начиная с 1961 года. Или что-то в этом роде.

У меня был тот же вопрос, но я также хотел, чтобы первая строка (заголовок) оставалась сверху. Поэтому мне нужно было использовать силу awk

PS тоже работает в cygwin или gitbash

Похоже, что в результате, 1\n20\n19. 2\n а не 20\n19. \2\n1\n .

Вы можете сделать это с vim stdin и stdout . Вы также можете использовать, ex чтобы быть POSIX-совместимым . vim это просто визуальный режим для ex . На самом деле, вы можете использовать ex с vim -e или vim -E (улучшенный ex режим). vim полезен, потому что в отличие от таких инструментов, как sed он, буферизует файл для редактирования, а sed используется для потоков. Вы могли бы использовать awk , но вам придется вручную буферизовать все в переменной.

Идея состоит в том, чтобы сделать следующее:

  1. Читать со стандартного ввода
  2. Для каждой строки переместите ее в строку 1 (для реверса). Команда есть g/^/m0 . Это означает глобально, для каждой строки g ; соответствует началу строки, которая соответствует чему-либо ^ ; переместить его после адреса 0, который является строкой 1 m0 .
  3. Распечатай все. Команда есть %p . Это означает для диапазона всех линий % ; напечатать строку p .
  4. Принудительно завершить работу без сохранения файла. Команда есть q! . Это значит бросить q ; силой ! .

Как сделать это многоразовым

Я использую скрипт, который я вызываю ved (например, vim editor sed ), чтобы использовать vim для редактирования stdin . Добавьте это к файлу, названному ved в вашем пути:

Я использую одну + команду вместо +'%p' +'q!' , потому что vim ограничивает вас до 10 команд. Таким образом, объединение их позволяет "$@" иметь 9 + команд вместо 8.

Читайте также: