awk sed if заявление

9

Я пытаюсь добавить 0 к началу, если есть "." на 2-м символе этой строки. Я не мог объединить эти два;

awk '{ print substr( $0, 2, 1 ) }' file.txt 

показывая второго персонажа

sed -ie "s/.\{0\}/0/" file.txt

добавив ноль в начало.

Там должно быть "если второй символ является точкой".

образец файла:

1.02.2017 23:40:00
10.02.2017 23:40:00

окончательный:

01.02.2017 23:40:00
10.02.2017 23:40:00
G.Ahmet
источник

Ответы:

12

Мы можем использовать sedили awkполностью или полностью решить проблему.


С sed:

$ sed 's/^.\./0&/' file.txt

Когда &происходит в замещающей части команды подстановки ( s), она будет расширена до той части строки ввода, которая соответствует шаблонной части команды.

Регулярное выражение ^.\.означает « соответствовать всем строкам, начинающимся с ( ^) произвольного символа ( .), за которым следует буквальная точка ( \.) ».

Если линия есть 1.02.2017 23:40:00, шаблон будет соответствовать и 1.будет заменен 01.на в начале строки.


С awk:

Опираясь на частичный awkкод в вопросе ...

Это, как указано, напечатает второй символ каждой строки ввода:

$ awk '{ print substr($0, 2, 1) }' file.txt

Мы можем использовать тот факт, что substr($0, 2, 1)возвращает второй символ и использовать его в качестве условия:

$ awk 'substr($0, 2, 1) == "." { ... }' file.txt

То, что входит в это, { ... }является кодом, который добавляет $0, который является содержанием текущей строки, с нулем, если предыдущее условие истинно:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 }' file.txt

Тогда нам просто нужно убедиться, что все строки напечатаны:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 } { print }' file.txt

substr($0, 2, 1) == "."Конечно, условие может быть также изменено на регулярное выражение (мы используем точно такое же выражение, как и в sedрешении):

$ awk '/^.\./ { $0 = "0" $0 } { print }' file.txt

Некоторые люди, которые думают, что «короче, всегда лучше», написали бы это как

$ awk '/^.\./ { $0 = "0" $0 } 1' file.txt

(и , вероятно , также удалить большинство пространства: awk '/^.\./{$0="0"$0}1' file.txt)

Кусалананда
источник
1
+1 Ваш последний пример AWK или ваш пример sed - правильные способы сделать это. Обратите внимание, для ясности, что это будет только один или другой.
Приостановлено до дальнейшего уведомления.
По моему мнению, «правильный» подход (который не возиться с пробелами и который в любом случае имеет меньший вес) является вашей окончательной версией sed 's/^.\./0&/' file.txt. Я думаю, вы должны поставить это в начале этого ответа. Тем не менее +1.
Wildcard
1
@Wildcard Мы стремимся, пожалуйста.
Кусалананда
5

С помощью sed:

sed -e "/^.\./s/^/0/" file.txt 

Шаблон /^.\./ищет любой символ и буквальную точку в начале строки ^, и, если они совпадают, sзамените начало строки на ноль, эффективно добавляя ноль к началу.

Выражение sed s/.\{0\}/0/несколько странно, оно соответствует нулю или большему количеству копий чего-либо и заменяется на ноль. Шаблон, конечно, будет совпадать в каждой позиции строки, но поскольку он s///заменяет только первое соответствие, он работает так, как вы предполагали. Хотя странный способ сделать это.


Или с awk, аналогичное регулярное выражение будет работать, чтобы соответствовать строке, но мы можем использовать substr:

awk 'substr($0, 2, 1) == "." {$0 = "0" $0} 1' file.txt 

Сначала мы проверяем, является ли второй символ точкой, а затем добавляем ноль в начало строки, если это так. Последний вызывает действие по умолчанию печати строки после любых изменений.

ilkkachu
источник
4

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

echo '1.2.2017 23:40:00' | sed 's/\./\//g' | xargs -0 date '+%m.%d.%Y %T' -d

будет выводить

01.02.2017 23:40:00

Команда sedв середине меняет точки на косые черты для ввода в date -d. Параметры формата позволяют выводить данные практически в любом формате. В %mчастности, это будет нулевое заполнение месяца, что, как кажется, вы пытаетесь сделать.

Как указывает Кусалананда:

Еще более компактный (GNU date и Bash): date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'

BMB
источник
2
Хорошо поймал! Еще более компактно (дата GNU и Bash):date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'
Кусалананда
Всякий раз, когда у меня есть косые черты в моих моделях, но нет труб s|\.|/|g. В противном случае, как отмечено выше: хороший улов, +1
Алекс Стрэджи
2

Стратегия, отличная от представленной в других ответах: вы можете использовать «.» в качестве разделителя полей.

awk -F. '$1 < 10 {printf "0"} {print}' /tmp/in.txt

Вы можете сыграть в гольф, чтобы:

awk -F. '$1<10{printf "0"}1' /tmp/in.txt

Для sed есть более короткая команда, представленная в другом (отличном) ответе.

Алекс Страгиес
источник
1
Альтернатива: awk -F. '{print ($1<10?0$0:$0)}' file
Георгий Василиу
1

С помощью sed это может быть

sed 's/^\(.\)\.\(.*\)/0\1.\2/'

Это будет использоваться ^для привязки к началу строки, затем захвата любого отдельного символа в группе, затем литерала ., затем чего-либо еще. Если мы совпадаем с тем, что печатаем a 0, то наша первая группа захвата (символ в начале строки), затем a .наша вторая группа захвата (остальная часть строки)

Эрик Ренуф
источник
Нет необходимости делать что-либо из этого захвата. &твой друг. Смотрите пример Кусалананды.
Приостановлено до дальнейшего уведомления.
@DennisWilliamson не требуется, но, учитывая, что уже есть другие примеры, это показывает еще одну особенность, sedкоторая может быть полезна в других ситуациях, а не только в этой конкретной проблеме
Эрик Ренуф,