Печатать все слова в строках файла в обратном порядке

Я не знаю, как заставить мой код работать для большего количества строк.

Это исходный файл t.txt:

Hello Earth Hello Mars 

Но я получаю следующий вывод:

 Mars Hello Earth Hello 

Мой ожидаемый результат:

 Earth Hello Mars Hello 

В общем, я хочу поддерживать порядок строк, но наоборот. Для ввода в общий регистр будет следующее:

 one two four five 

и ожидаемый результат:

 two one five four 

Мой код следующий:

 #!/bin/bash text=$(cat $1) arr=($text) al=${#arr[@]} let al="al-1" while (($al >= 0)) do echo -n "${arr[al]}" echo -n " " let al="al - 1" done echo 

3 Solutions collect form web for “Печатать все слова в строках файла в обратном порядке”

Все приведенные ниже примеры работают для общего случая, когда на линии имеется произвольное количество слов. Существенная идея везде одинакова: нам нужно читать строки за строкой и печатать слова в обратном порядке. AWK облегчает это, потому что у него уже есть все необходимые инструменты для обработки текста, сделанные программно, и наиболее переносимые – его можно использовать с любой производной awk, и в большинстве систем это есть. У Python также есть немало хороших утилит для обработки строк, которые позволяют нам выполнять эту работу. Я бы сказал, это инструмент для более современных систем. Баш, ИМХО, является наименее желательным подходом из-за мобильности, потенциальных опасностей и количества «обмана», которое необходимо выполнить.

AWK

 $ awk '{for(i=NF;i>=1;i--) printf "%s ", $i;print ""}' input.txt Earth Hello Mars Hello 

То, как это работает, довольно просто: мы зацикливаемся назад через каждое слово в строке, печатая слова, разделенные пробелом – это делается с помощью printf "%s ",$i функции printf "%s ",$i (для печати форматированных строк) и for-loop. Переменная NF соответствует числу полей. По умолчанию разделитель полей считается пространством. Начнем с установки переменной i для числа слов, а на каждой итерации – переменной. Таким образом, если в строке 3 слова, мы печатаем поле $ 3, затем $ 2 и $ 1. После последнего прохода переменная i становится 0, условие i>=1 становится ложным, и цикл завершается. Чтобы предотвратить объединение строк, мы вставляем новую строку, используя print "" . Кодовые блоки AWK {} обрабатываются для каждой строки в этом случае (если перед блоком кода есть условие соответствия, это зависит от соответствия для исполняемого кода кода или нет).

питон

Для тех, кто любит альтернативные решения, вот питон:

 $ python -c "import sys;print '\n'.join([ ' '.join(line.split()[::-1]) for line in sys.stdin ])" < input.txt Earth Hello Mars Hello 

Идея здесь немного отличается. < оператор сообщает вашей текущей оболочке перенаправить input.txt в поток stdin python, и мы читаем эту строку за строкой. Здесь мы используем понимание списка для создания списка строк – вот что делает [ ' '.join(line.split()[::-1]) for line in sys.stdin ] . Часть. ' '.join(line.split()[::-1]) принимает строку, разбивает ее на список слов, меняет список через [::-1] , а затем создает ' '.join() из него выделяется пространственно разделенная строка. В результате мы имеем список более крупных строк. Наконец, '\n'.join() делает еще большую строку, причем каждый элемент соединяется с помощью новой строки.

Короче говоря, этот метод основан на принципе перерыва и перестройки.

BASH

 #!/bin/bash while IFS= read -r line do bash -c 'i=$#; while [ $i -gt 0 ];do printf "%s " ${!i}; i=$(($i-1)); done' sh $line echo done < input.txt 

И тестовый прогон:

 $ ./reverse_words.sh Earth Hello Mars Hello 

Сам Bash не обладает мощными возможностями обработки текста. Что происходит здесь, так это то, что мы читаем файл по строкам через

 while IFS= read -r line do # some code done < text.txt 

Это частая техника и широко используется в сценариях оболочки для чтения вывода команды или текстового файла по строкам. Каждая строка хранится в переменной $line .

С внутренней стороны

 bash -c 'i=$#; while [ $i -gt 0 ];do printf "%s " ${!i}; i=$(($i-1)); done' sh $line 

Здесь мы используем bash с флагом -c для запуска набора команд, заключенных в одиночные кавычки. Когда используется -c , bash начнет назначать аргументы командной строки в переменные, начинающиеся с $0 . Поскольку $0 традиционно используется для обозначения имени программы, я сначала использую sh dummy.

Unquoted $line будет разбита на отдельные элементы из-за поведения, известного как расщепление слов. Разделение слов часто нежелательно в сценариях оболочки, и вы часто слышите, как люди говорят «всегда цитируйте свои переменные, например« $ foo ». В этом случае, однако, разделение слов желательно для обработки простого текста. Если ваш текст содержит что-то вроде $var , это может нарушить этот подход. Для этого и несколько других причин я бы сказал, что подход python и awk лучше.

Что касается внутреннего кода, это также просто: $line кавычек делится на слова и передается во внутренний код для обработки. Мы принимаем количество аргументов $# , храним их в переменной i и снова – распечатываем каждый элемент с использованием чего-то известного как переменная косвенность – это часть ${!i} (обратите внимание, что это багизм – он недоступен в других оболочки). И снова мы используем printf "%s " для распечатки каждого словарного пространства. Как только это будет сделано, echo будет вставлять новую строку.

По сути, этот подход представляет собой сочетание как awk, так и python. Мы читаем файл по строкам, но разделяем и властвуем каждую строку, используя несколько функций bash для выполнения задания.

Более простое изменение может быть выполнено с помощью команды GNU tac и снова проигрывание с разбиением слов. tac используется для обратной линии входного потока или файла, но в этом случае мы указываем -s " " использовать пробел как разделитель. Таким образом, var будет содержать список слов, разделенных символом строки в обратном порядке, но из-за того, что $var не цитируется, новая строка будет заменена пробелом. Обман, и снова не самый надежный, но работает.

 #!/bin/bash while IFS= read -r line do var=$(tac -s " " <<< "$line" ) echo $var done < input.txt 

Тесты:

И вот 3 метода с произвольными линиями ввода

 $ cat input.txt Hello Earth end of line Hello Mars another end of line abra cadabra magic $ ./reverse_words.sh line of end Earth Hello line of end another Mars Hello magic cadabra abra $ python -c "import sys;print '\n'.join([ ' '.join(line.split()[::-1]) for line in sys.stdin ])" < input.txt line of end Earth Hello line of end another Mars Hello magic cadabra abra $ awk '{for(i=NF;i>=1;i--) printf "%s ", $i;print ""}' input.txt line of end Earth Hello line of end another Mars Hello magic cadabra abra 

Дополнительно: перл и рубин

Такая же идея, как и с python – мы разделяем каждую строку на массив слов, реверсируем массив и распечатываем его.

 $ perl -lane '@r=reverse(@F); print "@r"' input.txt line of end Earth Hello line of end another Mars Hello magic cadabra abra $ ruby -ne 'puts $_.chomp.split().reverse.join(" ")' < input.txt line of end Earth Hello line of end another Mars Hello magic cadabra abra 

Просто поменяйте слова, используя awk :

 awk '{print $2, $1}' 

Пример:

 % cat bar.txt Hello Earth Hello Mars % awk '{print $2, $1}' bar.txt Earth Hello Mars Hello 

Обязательное решение sed

Следующая программа GNU sed использует цикл для перемещения каждого слова (начиная с первого) в конце строки. Более подробные сведения вставляются в код в виде комментариев.

 sed -r ' # Mark the current end of the line by appending a LF character ("\n") G # Main loop: move the first word of the line just after the LF # and repeat until the LF is at the beginning of the line :loop s/([^[:space:]]+)(.*\n)/\2\1 / t loop # Remove remaining spaces up to the LF and the superfluous trailing space s/.*\n| $//g ' 

Только для записи:

 sed -r 'G; :loop; s/(\S+)(.*\n)/\2\1 /; t loop; s/.*\n| $//g' 

Контрольная работа:

 $ sed -r '...' <<< "The quick brown fox jumps over the lazy dog" 

… дает:

 quick The jumps fox brown over dog lazy the 

Портативно (POSIXly):

 sed ' G :loop s/\([^[:space:]]\{1,\}\)\(.*\n\)/\2\1 / t loop s/ $// s/.*\n//' 
  • Как сортировать и присоединяться одновременно?
  • Добавление строки в файла конфигурации
  • извлекать серверные блоки из Nginx conf
  • делает головной вход> вывод копирует все невидимые символы в новый файл?
  • Как связать номер строки с файлом в файл результатов выходного файла diff?
  • Показать соотношение для всех доступных разрешений
  • Bash Как я могу обернуть текст на определенное количество разделенных пространством входов
  • Как найти наиболее частое слово каждого файла в каталоге?
  • Умный способ выполнить аналогичную замену (не достаточно простую для diff) в нескольких файлах?
  • Все возможные перестановки слов в разных файлах попарно
  • Команда для печати нескольких последовательных строк из середины файла
  • Interesting Posts

    mutt: определить, какие заголовки отображаются (в компоновке)

    Диагональный вывод файла

    USB-флеш-накопитель с жестко закодированным разделом

    Застрял в цикле в приглашении входа в систему после изменения оболочки на zsh

    Установка Java JDK в busybox в контейнере LXC – java / lang / NoClassDefFoundError: java / lang / Object

    Повторная кодировка видео-библиотеки в x265 (HEVC) без потери качества

    Автоматически копировать определенную папку с каждой удаленной машины на главную машину

    Есть ли простой способ скопировать системные настройки с установки EOL на новую версию?

    Могу ли я установить дистрибутив на один раздел при использовании дистрибутива, установленного на другом?

    Что означают флаги в / proc / cpuinfo?

    Как я могу заставить меньше останавливать буферизацию ввода строки за строкой?

    Сценарий Bash: команда ls не найдена

    Используя startx на Fedora 17, пользователь без полномочий root не может присоединиться к новым беспроводным сетям – как исправить?

    Является ли nouveau полностью свободным от несвободного кода?

    NixOS: Как мне изменить свою группу и очистить плохие конфигурации?

    Linux и Unix - лучшая ОС в мире.