Заменить символ, кроме последних x входов

У меня есть файл с кучей имен хостов, коррелированный с IP-адресами, который выглядит так:

x-cluster-front-1 192.168.1.2 x-cluster-front-2 192.158.1.10 y-cluster-back-1 10.1.11.99 y-cluster-back-2 10.1.157.38 int.test.example.com 59.2.86.3 super.awesome.machine 123.234.15.6 

И я хочу, чтобы это выглядело так:

  • Bash: условная новая строка в PS1 ломает typeahead
  • Почему это «пока прочитано» работает в терминале, но не в сценарии оболочки?
  • Добавить столбцы в текстовый файл с заданным интервалом в Bash
  • Выполнение функции скрипта Bash с помощью Sudo
  • как я могу добавить (вычесть и т. д.) два числа с bash?
  • Как я могу увидеть, какая команда была фактически запущена в оболочке, через псевдоним или функцию
  •  x-cluster-front-1 192.168.1.2 x-cluster-front-2 192.158.1.10 y-cluster-back-1 10.1.11.99 y-cluster-back-2 10.1.157.38 int-test-example-com 59.2.86.3 super-awesome-machine 123.234.15.6 

    Мой вопрос: как я могу заменить. (точек) из первого столбца с – (строка), чтобы облегчить сортировку по второму столбцу. Я думал использовать sed для замены точек до первого пробела или замены каждой точки, но последние три, но у меня проблемы с пониманием регулярных выражений и sed … я могу выполнять простые замены, но это происходит над моей головой: D.

    Это часть большого скрипта, который я писал в bash. Я застрял в этой части …

  • Как переопределить функцию bash с точки зрения старого определения?
  • Показывать только stderr на экране, но записывать как stdout, так и stderr в файл
  • Легкий способ разбора формата даты syslog
  • Команда ведет себя по-разному при сохранении в файле * .sh
  • Как определить среду рабочего стола в сценарии bash?
  • Как сбросить все ключи привязки в моем Bash?
  • 9 Solutions collect form web for “Заменить символ, кроме последних x входов”

    Вы можете использовать AWK

     awk '{gsub(/-/,".",$1);print}' infile 

    объяснение

    По умолчанию awk разбивает строку по пробелам. Таким образом, первый столбец строки ( $1 в awk -ese) будет тем, который вы хотите выполнить подстановками. Для этого вы можете использовать:

      gsub(regex,replacement,string) 

    для выполнения требуемой замены.

    Обратите внимание, что gsub поддерживается только для gawk и nawk но во многих современных дистрибутивах awk – это программная ссылка на gawk .

    Если вам нужно сделать замены в первом поле, лучше всего использовать решение awk Rahul, но будьте осторожны, это может повлиять на интервал (поля переписываются с одним пробелом между ними).

    Вы можете избежать этого, написав вместо этого:

     perl -pe 's|\S+|$&=~tr/./-/r|e' file 

    Флаг -p означает «читать входной файл по строке и печатать каждую строку после применения сценария, заданного -e ». Затем замените ( s|pattern|replacement| ) на первую последовательность непространственных символов ( \S+ ) совпадающим шаблоном ( $& ) после замены всех . с - . Хитрость заключается в использовании s

    e где оператор e будет оценивать выражение в качестве замены. Таким образом, вы можете иметь одну замену ( tr/./-/ ), применяемую к совпадению ( $& ) предыдущего ( s

    e ).

    Если вам нужно заменить каждый . с - за исключением последних 3 последних, с GNU sed и при условии, что у вас есть команда rev :

     rev file | sed 's/\./-/4g' | rev 

    Sed – не самый простой инструмент для работы – см. Другие ответы на лучшие инструменты, но это можно сделать.

    Заменить . by - только до первого пространства, используйте s в цикле.

     sed -e ' : a # Label "a" for the branching command s/^\([^ .]*\)\./\1-/ # If there is a "." before the first space, replace it by "-" ta # If the s command matched, branch to a ' 

    (Обратите внимание, что некоторые реализации sed не поддерживают комментарии в той же строке. GNU sed делает.)

    Вместо этого выполнить замену до последнего места:

     sed -e ' : a # Label "a" for the branching command s/\.\(.* \)/-\1/ # If there is a "." before the last space, replace it by "-" ta # If the s command matched, branch to a ' 

    Другой метод использует пространство для хранения sed. Сохраните бит, который вы не хотите изменять в пространстве удержания, выполните свою работу, а затем вспомните пространство удержания. Здесь я разделил строку в последнем пространстве и заменил точки пунктиром в первой части.

     sed -e ' h # Save the current line to the hold space s/.* / / # Remove everything up to the last space x # Swap the work space with the hold space s/[^ ]*$// # Remove everything after the last space y/./-/ # Replace all "." by "-" G # Append the content of the hold to the work space s/\n// # Remove the newline introduced by G ' 

    Поскольку Рахул дал вам канонический ответ для вашего случая использования, я подумал, что я бы наткнулся на ответную проблему: заменяя все, кроме последних x появлением регулярного выражения:

     perl -pe ' $count = tr{.}{.}; # Count '.' on the current line $x = 3; next LINE if $count <= $x; while(s{\.}{-}){ # Substitute one '.' with a '-' last if ++$i == $count - $x # Quit the loop before the last x substitutions } $i = 0 ' your_file 

    Вышеприведенный код (проверенный) не предполагает, что у вас есть поля, разделенные пробелами. Он заменит все точки на линии тире, за исключением последних 3 точек. Замените 3 в коде по своему вкусу.

    Для этого вы можете использовать множество различных инструментов. Рахул Патил уже дал вам gawk поэтому вот несколько других:

    • Perl

       perl -lane '$F[0]=~s/\./-/g; print "@F"' file 

      Переключатель -a заставляет perl автоматически разбивать входные строки на пробелы и сохранять полученные поля в массиве @F . Поэтому первое поле будет $F[0] поэтому мы заменим ( s/// ) все вхождения . с - в первом поле, а затем распечатать весь массив.

    • оболочка

        while read -rab; do printf "%s %s\n" "${a//./-}" "$b"; done < file 

      Здесь цикл while считывает файл и автоматически разбивается на whitespace. Это создает два поля: $first и $rest . Конструкция ${first//pattern/replacement} заменяет все вхождения pattern replacement .

    Я считаю, что это немного легче читать, чем большое неприятное регулярное выражение. В основном я просто разделил строку на два поля в пробеле и использовал sed в первой части.

     while read -r host ip; do echo "$(sed 's/\./-/g' <<< "$host") $ip" done < input_file 

    В зависимости от вашей оболочки вы также можете использовать $ {host //./-} вместо команды sed.

     sed 's/\./-/' <file name> 

    Без использования g в конце команды вы можете это сделать … Это просто заменит 1-е появление шаблона

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