Замените первый столбец файла на вывод команды

Это полезно, когда используются неанглийские (неascii) символы. Пример ch, который вы упомянули, является диграфом, т.е. некоторые языки имеют в своем алфавите букву, которая представлена/может быть представлена двумя буквами английского алфавита.

Когда вы используете [.ch.] в регексп, вы, по сути, говорите: "Я ожидаю неанглийскую входную последовательность с диграфом ch. Я хочу, чтобы мой регексп соответствовал единственному символу ch". Мой язык программирования/движок регекса/клавиатура не позволяют мне написать знак этого диграфа, поэтому я набираю [.ch.]. Я не имею в виду c, за которым следует h. Пожалуйста, найдите только те случаи, когда диграф встречается в виде одного символа"

.

[[.ch.]] означает, что диграф является частью набора символов. В данном случае фактически только один символ. Просто стандартная нотация regexp.

5
13.04.2017, 15:36
6 ответов

Давайте воспользуемся уже существующим циклом (на который я еще не смотрел, но который, похоже, выполняет свою работу):

for i in $(awk '{print $1}' filedate.txt); do date -d "$i"  +%d/%m/%Y; done

А затем заправьте мой ответ на этот другой вопрос с небольшими изменениями:

for i in $(awk '{print $1}' filedate.txt); do date -d "$i"  +%d/%m/%Y; done |
paste - <( cut -d ' ' -f 2- filedate.txt )

Результат:

01/01/2007      10.2317  79.1638   6.0  26.7  20.9   0.8  14.0  98.6
02/01/2007      10.2317  79.1638   5.6  26.5  20.8   1.9  13.6  98.0
03/01/2007      10.2317  79.1638   7.5  27.7  20.8   0.1  15.8  96.4
04/01/2007      10.2317  79.1638   8.1  26.0  19.6   0.0  15.5  94.1

Короче, без цикла:

date -f <( cut -d ' ' -f 1 filedate.txt ) +"%d/%m/%Y" |
paste - <( cut -d ' ' -f 2- filedate.txt )

Без трубы:

paste <( date -f <( cut -d ' ' -f 1 filedate.txt ) +"%d/%m/%Y" ) \
      <( cut -d ' ' -f 2- filedate.txt )

Все эти примеры, очевидно, требуют либо ] bash или ksh или любая другая оболочка, которая понимает подстановки процессов. Также требуется дата GNU .

См. мой ответ на этот другой вопрос для объяснения того, как это работает.

2
27.01.2020, 20:34

Если у вас есть GNU awk ( gawk ), вы можете заменить столбец, используя вывод команды, используя форму getline / variable / pipe из getline для вывода функции date :

gawk '{"date +%d/%m/%Y -d" $1 | getline $1} 1' file

Однако, если вы просто хотите изменить формат даты столбца, вы можете сделать это изначально, используя внутренний Функции mktime и strftime :

gawk '{
  d = sprintf("%d %02d %02d 0 0 0", substr($1,1,4), substr($1,5,2), substr($1,7,2));
  t = mktime(d);
  $1 = strftime("%d/%m/%Y", t);
  } 1' file

хотя в этом случае вы можете выполнить необходимое преобразование, используя простые манипуляции со строками (которые должны работать в любом варианте awk ):

$ mawk '{$1 = sprintf("%02d/%02d/%02d", substr($1,7,2), substr($1,5,2), substr($1,1,4))} 1' file
01/01/2007 10.2317 79.1638 6.0 26.7 20.9 0.8 14.0 98.6
02/01/2007 10.2317 79.1638 5.6 26.5 20.8 1.9 13.6 98.0
03/01/2007 10.2317 79.1638 7.5 27.7 20.8 0.1 15.8 96.4
04/01/2007 10.2317 79.1638 8.1 26.0 19.6 0.0 15.5 94.1
2
27.01.2020, 20:34
sed 's| *\(....\)\(..\)\(..\)|\2/\3/\1|' < in > out
2
27.01.2020, 20:34

Модификатор GNU sed e val для команды s позволит вам использовать date для преобразования дат по мере необходимости:

sed -r 's|(\S+)(.*)|date -d \1 "+%d/%m/%y \2"|e'

Подставляемое выражение правильно сформированная команда даты. Модификатор e заставляет это выполняться для каждой строки, и буфер шаблона (и, следовательно, вывод) заменяется выводом каждой команды даты.

2
27.01.2020, 20:34

Хотя это может показаться не лучшим решением, я бы выбрал другое решение, например, используя такую ​​обработку параметров bash:

gv@debi64:$ a="20070101"; b="${a: -2:2}/${a: -4:2}/${a: 0:4}";echo $b
01/01/2007

Затем я мог бы прочитать файл и используя что-то вроде sed -i "s / $ a / $ b / g" , я могу добиться того, что вам нужно:

gv@debi64:$ cat a.txt
20070101 10.2317  79.1638   6.0  26.7  20.9   0.8  14.0  98.6
20070102 10.2317  79.1638   5.6  26.5  20.8   1.9  13.6  98.0
20070103 10.2317  79.1638   7.5  27.7  20.8   0.1  15.8  96.4
20070104 10.2317  79.1638   8.1  26.0  19.6   0.0  15.5  94.1

gv@debi64:$ while IFS=" " read -r df rest;do ndf="${df: -2:2}/${df: -4:2}/${df: 0:4} "; sed -i "s#$df#$ndf#g" a.txt;done <a.txt

gv@debi64:$ cat a.txt
01/01/2007  10.2317  79.1638   6.0  26.7  20.9   0.8  14.0  98.6
02/01/2007  10.2317  79.1638   5.6  26.5  20.8   1.9  13.6  98.0
03/01/2007  10.2317  79.1638   7.5  27.7  20.8   0.1  15.8  96.4
04/01/2007  10.2317  79.1638   8.1  26.0  19.6   0.0  15.5  94.1
1
27.01.2020, 20:34

Если желаемое преобразование - это просто переупорядочивание существующей информации, почему бы не сделать

awk '{ $1=sprintf("%02i/%02i/%04i",
     substr($1, 7, 2), substr($1, 5, 2), substr($1, 1, 4)) }1' file

Мы поднимаем подстроки из первого поля и повторно собираем их в новое значение для первого поля, а затем печатаем всю строку ввода как обычный. (Одиночный 1 после закрывающей фигурной скобки является стандартной идиомой Awk для безусловной печати.)

Вы, вероятно, пожалеете о преобразовании идеально хороших машиночитаемых дат в "удобочитаемых человеком" правда, очень скоро.

2
27.01.2020, 20:34

Теги

Похожие вопросы