Как получить "awk", чтобы изменить только определенные строки файла, а не весь файл? - PullRequest
0 голосов
/ 20 апреля 2020

Я хотел бы повторно использовать этот код awk , чтобы правильно использовать заглавные буквы некоторых аудиофайлов. Этот код не только использует заглавные буквы, но и следует некоторым правилам использования заглавных букв, как описано в связанном вопросе.

Проблема состоит в том, как изменить этот код, чтобы использовать заглавные буквы только для строк "TITLE" и не весь файл. Например, с этим простым листом подсказки:

FILE "Two The Beatles Songs.wav" WAVE
  TRACK 01 AUDIO
    TITLE "dig A pony"
    PERFORMER "The Beatles"
    INDEX 01 00:00:00
  TRACK 02 AUDIO
    TITLE "from me to you"
    PERFORMER "The Beatles"
    INDEX 01 03:58:02

И с простым для l oop плюс код awk, например, что-то вроде этого:

#!/bin/sh
for cue_file in *.cue
do
  awk 'BEGIN{split("a the to at in on with and but or",w); for(i in w)nocap[w[i]]}function cap(word){return toupper(substr(word,1,1)) tolower(substr(word,2))}{for(i=1;i<=NF;++i){printf "%s%s",(i==1||i==NF||!(tolower($i) in nocap)?cap($i):tolower($i)),(i==NF?"\n":" ")}}' "$cue_file" > ~/temp_cue_file && mv ~/temp_cue_file "$cue_file"
done

Результат после запуск сценария должен быть:

FILE "Two The Beatles Songs.wav" WAVE
  TRACK 01 AUDIO
    TITLE "Dig a Pony"
    PERFORMER "The Beatles"
    INDEX 01 00:00:00
  TRACK 02 AUDIO
    TITLE "From Me to You"
    PERFORMER "The Beatles"
    INDEX 01 03:58:02

То есть TITLE "Dig a Pony" вместо TITLE "dig A pony". И TITLE "From Me to You" вместо TITLE "from me to you".

Запрос:

  1. Как объяснялось ранее, сценарий оболочки должен изменять только строки TITLE (все из них), а не остальные.
  2. Сценарий оболочки должен запускаться под оболочкой POSIX sh. В моем случае FreeBSD.
  3. Будет полезен однострочный код awk.
  4. Чтобы следовать тем же «правилам прописной буквы» , что и для связанного вопроса (и что предоставленный awk следует). То есть:

    • С заглавными буквами все слова, за исключением:
    • Строчные все статьи (a, the), предлоги (to, in, with) и координационные союзы ( и, но, или)
    • С заглавной буквы первого и последнего слова в названии, независимо от части речи

Как можно адаптировать код awk к получить этот результат?

Спасибо.


Предыдущий однострочный код awk, кажется расширенным в связанном ответе:

BEGIN { split("a the to at in on with and but or", w)
        for (i in w) nocap[w[i]] }

function cap(word) {
    return toupper(substr(word,1,1)) tolower(substr(word,2))
}

{
  for (i=1; i<=NF; ++i) {
      printf "%s%s", (i==1||i==NF||!(tolower($i) in nocap)?cap($i):tolower($i)),
                     (i==NF?"\n":" ")
  }
}

1 Ответ

1 голос
/ 20 апреля 2020

Не могли бы вы попробовать следующее.

awk '
BEGIN{
  num=split("a the to at in on with and but or",array," ")
  for(i=1;i<=num;i++){
    smallLetters[array[i]]
  }
}
/TITLE/{
  for(i=2;i<=NF;i++){
    if(tolower($i) in smallLetters){
      $i=tolower(substr($i,1,1)) substr($i,2)
    }
    else{
      if($i~/^\"/){
        $i=substr($i,1,1) toupper(substr($i,2,1)) substr($i,3)
      }
      else{
        $i=toupper(substr($i,1,1)) substr($i,2)
      }
    }
  }
}
1
'  Input_file

Объяснение: Добавление подробного объяснения для вышеуказанного кода.

awk '                                                                         ##Starting awk program from here.
BEGIN{                                                                        ##Starting BEGIN section of this program from here.
  num=split("a the to at in on with and but or",array," ")                    ##Creating array for all words needs to be of lower size.
  for(i=1;i<=num;i++){                                                        ##Running a for loop from i=1 to tillvalue of num(length of array).
    smallLetters[array[i]]                                                    ##Creating an array named smallLetters with index of variable i here.
  }
}
/TITLE/{                                                                      ##Checking condition if a line contains string TITLE then do following.
  for(i=2;i<=NF;i++){                                                         ##Running a for loop from 2nd field to last field of line.
    if(tolower($i) in smallLetters){                                          ##Checking condition if lower case current field is present in array smallLetters.
      $i=tolower(substr($i,1,1)) substr($i,2)                                 ##Changing current field to lower case for 1st letter and keeping rest same as it is.
    }
    else{                                                                     ##If current field is NOT in array then do following.
      if($i~/^\"/){                                                           ##Checking if field starts from " then do following.
        $i=substr($i,1,1) toupper(substr($i,2,1)) substr($i,3)                ##Only make 2nd letter Capital since 1st is "
      }
      else{
        $i=toupper(substr($i,1,1)) substr($i,2)                               ##Else make1st character capital and keep as it is.
      }
    }
  }
}
1                                                                             ##Printing edited/non-edited lines here.
'  Input_file                                                                 ##Mentioning Input_file name here.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...