Как заменить символы только в определенных строках?

С помощью ls, хотя вы не всегда сможете получить время, вы должны быть в состоянии получить дату (год, месяц и день месяца).

В локали C вывод даты в ls -l должен быть либо Mmm dd HH:MM для недавних файлов (и вы должны быть в состоянии вывести год (либо этот год, либо предыдущий) или Mmm dd YYYY для старых файлов или файлов с временем модификации в будущем. Таким образом, вы всегда сможете получить дату (YYYY-mm-dd) из этого:

eval "$(date +'year=%Y month=%m')"
LC_ALL=C ls -dn file | awk -v y="$year" -v m="$month" '{
  month = index("--JanFebMarAprMayJunJulAugSepOctNovDec", $6) / 3
  day = $7
  if ($8 ~ /:/)
    year = y - (month > m)
  else
    year = $8
  printf "%04d-%02d-%02d\n", year, month, day
  exit}'

Теперь, если вам нужно полное время модификации с максимальной точностью, боюсь, что для этого нет стандартной команды.

Вы можете найти некоторые реализации ls, которые имеют опции для этого (ls --full-time в GNU ls или -... D с FreeBSD ls, например)

Существует ряд различных и несовместимых реализаций команды stat (IRIX, zsh builtin, GNU, BSD), которые могут дать вам это.

Или вы можете использовать -printf предикат GNU find. Или опцию -r GNU date.

Не все реализации дадут вам субсекундную детализацию. Остерегайтесь часовых поясов и DST, поскольку в зависимости от выбранного формата и часового пояса, в котором вы находитесь, данный вывод может быть неоднозначным и относиться к более чем одной возможной дате.

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

  • zsh stat: stat -F '%Y-%m-%d %T.%N %z' +mtime file
    1992-05-13 14:57:00.123368710 +0100
  • GNU stat stat -c %y file
    1992-05-13 14:57:00.123368710 +0100
  • BSD stat: stat -t '%F %T %z' -f %Sm file
    1992-05-13 14:57:00 +0100
  • IRIX stat: stat -m file
  • GNU find: find file -prune -printf '%TF %TT %Tz\n'
    1992-05-13 14:57:00.1233687100 +0100
  • GNU date: date -r file '+%F %T.%N %z'
    1992-05-13 14:57:00.123368710 +0100
  • FreeBSD ls: ls -D '[%F %T %z]' -l file
    -r-xr-xr-x 2 bin bin 372298 [1992-05-13 14:57:00 +0100] file
  • GNU ls: ls --full-time -l file
    -r-xr-xr-x 2 bin bin 372298 1992-05-13 14:57:00.123368710 +0100 file
  • ast-open ls: ls -Z '%(mtime:time=%F %T.%N %z)s'
    1992-05-13 14:57:00.123368710 +0100

AIX, которую, судя по вашему ls синопсису, вы используете, имеет команду istat (AIX 5. 3 man page), которая отображает даты полностью (без субсекундной детализации, и неоднозначно, если вы не заставите TZ заменить UTC0), хотя ее не так легко разобрать:

$ LC_ALL=C TZ=UTC0 istat file
Inode 10360 on device 10/6    File
Protection: r-xr-xr-x
Owner: 2(bin)     Group: 2(bin)
Link count: 2     Length 372298 bytes

Last updated:  Wed May 13 14:08:13 1992
Last modified: Wed May 13 13:57:00 1992
Last accessed: Sun Jan 31 15:49:23 1993

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

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

$ perl -MPOSIX -le 'print strftime("%Y-%m-%d %T %z", localtime((lstat(shift))[9]))' file
1992-05-13 14:57:00 +0100

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

5
16.01.2017, 21:51
3 ответа

Сложность заключается в том, что если вы замените все ' на ", а затем все " на ' , вы останетесь только с '. Итак, сначала вам нужно заменить ' чем-то другим, например, символом NULL ( \ 0 ), которого, как вы можете смело предположить, не будет во входном файле, - затем « на ', а затем снова замените это что-то еще на » . Например, в perl:

$ perl -pe "if(/KEYWORD){s/'/\0/g; s/\"/'/g; s/\0/\"/g}" file
KEYWORD_1 table name column = 'string' AND column = 'string'
Additional text
      .
      .
      .
KEYWORD_2 text "text in quote" etc. 

Explanation

  • -pe : p rint каждую строку ввода после применения сценария, заданного -e .
  • if (/ KEYWORD /) {something} : выполните something , только если эта строка соответствует KEYWORD .
  • s / foo / bar / g : замените все вхождения foo в строке на bar . g означает «глобальный». Без него будет заменено только первое вхождение в каждой строке.

Обратите внимание, что, поскольку сам скрипт заключен в двойные кавычки, двойные кавычки внутри скрипта необходимо экранировать ( \ ").


Как указано в комментариях, есть более прямой способ В первую очередь мне следовало подумать:

perl -pe "tr/'\"/\"'/ if /^KEYWORD/" file

Оператор tr транслитерирует списки символов. Общий формат - tr / searchlist / replacementlist / . Таким образом, он заменит все ' с « и все » с ' только в строках, соответствующих KEYWORD .

3
27.01.2020, 20:35

Немного грубая, но работающая переменная GNU awk:

$ awk -v sq="'" '/KEYWORD/{if ($0~sq){ gsub(sq,"\"")} else if ($0~"\"") gsub(/\"/,sq)};1' input.txt                      
KEYWORD_1 table name column = 'string' AND column = 'string'
Additional text
      .
      .
      .
KEYWORD_2 text "text in quote" etc.

sq используется для представления одинарных кавычек, поскольку встраивание ее в сам кодовый блок - это немного неудобно для awk. Основная идея заключается в том, что мы ищем шаблон, если шаблон найден - мы принимаем решение, что заменить. Final 1 просто указывает awk напечатать строки.

Что касается вывода его в файл, просто используйте оператор оболочки > , чтобы перенаправить текст во временный файл и заменить старый файл новым с помощью команды mv .

0
27.01.2020, 20:35

Замена символов

Замена набора символов на другой набор символов обычно является задачей для команды tr, но поскольку вы хотите сделать это только в определенных строках, это лучше всего сделать с помощью sed, которая имеет команду y, аналогичную tr:

sed -e "/^KEYWORD_1/  y/\"/'/" \
    -e "/^KEYWORD_2/  y/'/\"/" \
    file

Каждая команда sed здесь начинается с селектора строки /^KEYWORD/, который инструктирует sed работать только со строкой, соответствующей шаблону между /. Здесь шаблоны начинаются с символа ^, чтобы указать, что они должны быть найдены в начале строки.

После селектора строк следует команда подстановки sed y/set1/set2/g, которая заменяет каждое вхождение символа в set1 на символ, занимающий ту же позицию в set2.

Замена символов

Теперь, если в одной строке вы хотите заменить каждый " на ' и одновременно каждый ' на ", вы можете использовать только одну команду:

sed -e "/^KEYWORD_1\|^KEYWORD_2/  y/\"'/'\"/" file
7
27.01.2020, 20:35

Теги

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