Итерация с awk по нескольким тысячным файлам и запись в одни и те же файлы за один или два запуска - PullRequest
1 голос
/ 18 октября 2019

У меня много файлов в собственном каталоге. Все они имеют одинаковую структуру имен:

2019-10-18-42-IV-Friday.md
2019-10-18-42-IV-Saturday.md
2019-10-18-42-IV-Sunday.md
2019-10-18-43-43-IV-Monday.md
2019-10-18-42-IV Tuesday.md

и т. Д.

Это подробно: гггг-мм-дд-дд-неделя года фактический квартал-день недели. md

Я хочу записать одну строку в каждый файл как вторую строку: с помощью awk я хочу извлечь и развернуть даты из имени файла, а затем записать их в соответствующий файл.

Это тот момент, когда я терплю неудачу.

%!awk -F"-"-" '{print "Today is $6 ", the " $3"."$2"."$1", Kw "$4", in the" $5 ". Quarter."}'

Это хорошо работает, я получаю предложение, которое я хочу записать в файлы.

Так что все это в цикле:

ze.sh  
 #!/bin/bash                                                                 
 for i in *.md;                                                              
       j = awk -F " " '{ print "** Today is " $6 ", the" $3"." $2"." $1", Kw " $4 ", in the " $5 ". Quarter. **"}' $i 
 Something with CAT, I suppose.                                                             

end 

Что нужно сделать, чтобы переменная i перебирала все файлы, извлекала значения для j из $ i, а затем записывала $ j ввторая строка каждого файла?

Большое спасибо за вашу помощь.

[Использование manjaro linux и bash] GNU bash, версия 5.0.11 (1) -релиз (x86_64-pc-linux)-gnu) версия Linux 5.2.21-1-MANJARO

Ответы [ 4 ]

1 голос
/ 18 октября 2019

Не могли бы вы попробовать следующее (еще не проверял, для этого нужен GNU awk). Для записи даты во 2-й строке я выбрал тот же формат, в котором ваш Input_file содержит дату.

awk -i inplace '
FNR==2{
  split(FILENAME,array,"-")
  print array[1]"-"array[2]"-"array[3]
}
1
' *.md

Если возможно, попробуйте сначала без опции -i inplace, чтобы изменения не были сохранены в Input_file и один развы довольны результатами, тогда вы можете добавить его, как показано выше, в код для внесения изменений на месте в файл Input_file.

Сведения о поддерживаемых версиях awk для обновления на месте см. в опубликованной ссылке James sir.

Сохранитьизменения на месте с awk

0 голосов
/ 18 октября 2019

Это лучшее решение для меня, особенно потому, что оно справляется с разными разделителями.

Большое спасибо всем, кто интересовался этим вопросом, и особенно тем, кто разместил решения.

Хотелось бы, чтобы я не делал это так сложно, потому что набрал неверные данные.

Теперь это "мой" вариант решения:

for filename in *.md; do 
  IFS='-. ' read year month day week q dayname rest <<< "$filename"
  line="Today is $dayname, the $day.$month.$year, Kw $week, in the $q. Quarter."
  sed -i.bak -e "1 a\\"$'\n'"$line"$'\n' "$filename" && rm *.bak;
  done

Из-за нескольких разделителей полей,результат лучше всего использовать.

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

Я очень удивлен и рад тому, как быстро я получил очень хорошие ответы как новичок. Надеюсь, я смогу что-то вернуть.

И я также поражен, сколько разных решений возможно для возникающих проблем.

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

Особенно сильно пострадала моя память;Я часто не помню, что я делал вчера, узнал, что еще нужно сделать.

Вот почему я создавал дневные файлы до 31.12.2030, с шаблоном уценки для каждого дня. Затем я записываю, что я сделал и чему научился в те дни, и что еще предстоит сделать.

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

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

Это достаточно быстро. Изменения в 4097 файлов, как описано выше, заняли менее 2 секунд на моем ноутбуке i5 (Ram 12 ГБ, SSD).

Поиск с помощью fzf по всем файлам также очень быстрый. Я могу просто конвертировать файлы и выводить их как мне нужно.

Моя память не вернется после этого, но у меня есть возможность записать то, что я забыл.

Спасибоочень за вашу помощь и внимание.

0 голосов
/ 18 октября 2019

Для обновления файла на месте sed лучше подходит, чем awk, потому что:

  • Вам не нужна последняя версия, более старые версии тоже могут это сделать
  • Может работать как с GNU, так и с BSD -> более переносимым

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

2019-10-18-42-IV-Friday.md
2019-10-18-42-IV-Saturday.md
2019-10-18-42-IV-Sunday.md
2019-10-18-43-43-IV-Monday.md
2019-10-18-42-IV Tuesday.md

Для первых 3 строк это простое выражение будет работать:

IFS=-. read year month day week q dayname rest <<< "$filename"

В последней строке перед именем дня недели вместо - стоит пробел, но это легко исправить:

IFS='-. ' read year month day week q dayname rest <<< "$filename"

Строку 4 сложнее исправить, поскольку она имеетразное количество полей. Чтобы обработать дополнительное поле, мы должны добавить дополнительный переменный член:

IFS='-. ' read year month day week q dayname ext rest <<< "$filename"

И затем, если мы можем предположить, что второй 43 в этой строке можно игнорировать, и мы можем просто сдвинуть аргументы,тогда мы используем условное значение $ext. То есть для большинства строк значение ext будет md (расширение файла). Если значение отличается, это означает, что у нас есть дополнительное поле, и мы должны сдвинуть значения:

if [[ $ext != "md" ]; then
    q=$dayname
    dayname=$ext
fi

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

line="Today is $dayname, the $day.$month.$year, Kw $week, in the $q. Quarter."

Наконец, мы можем сформулировать оператор sed, например, чтобы добавить нашу пользовательскую отформатированную строку после первой, в идеале таким образом, чтобы работать как с GNU, так и с BSD-вариантами sed.

Это будет работать одинаково с версиями GNU и BSD:

sed -i.bak -e "1 a\\"$'\n'"$line"$'\n' "$filename" && rm *.bak

Обратите внимание, что созданы .bak файлы резервных копий, которые необходимо удалить вручную.

Если вы неЕсли вы не хотите создавать файлы резервных копий, то, боюсь, вам нужно использовать немного другой формат для разновидностей GNU и BSD:

# GNU
sed -i'' -e "1 a\\"$'\n'"$line"$'\n' "$filename"

# BSD
sed -i '' -e "1 a\\"$'\n'"$line"$'\n' "$filename"

На самом деле, если вам требуется только поддержка разновидности GNU, тогда более простая форматоже будет работать:

sed -i'' "1 a$line" "$filename"

Все это можно объединить в цикл for filename in *.md; do ...; done.

0 голосов
/ 18 октября 2019

Возможно, вы захотите ввести имя файла в сценарий AWK, используя «-» для разделения компонентов.

Этот сценарий предполагает, что к файлу необходимо добавить вторую строку вывода AWK:

for i in *.md ; do
    echo $i | awk -F- 'AWK COMMAND HERE' >> $i
done

Если новый текст должен быть вставлен (как вторая строка) в новый файл, можно использовать программу sed для обновления файла (используя редактирование на месте '-i'). Что-то вроде

for i in *.md ; do
    mark=$(echo $i | awk -F- 'AWK COMMAND HERE')
    sed -i -e "2i$mark" $i
done
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...