Как вырезать дату и время в Unix Scripting

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

***  WARNING  ***  The  locale  specified  by the environment affects sort order.
Set LC_ALL=C to get the traditional sort order that uses native byte values.

Собственное значение байта обычно означает значение ASCII, поэтому цифры идут перед прописными буквами, которые идут перед строчными буквами. Но порядок по-прежнему посимвольный, поэтому 10предшествует 2, потому что 1предшествует 2.

Когда указана опция -nили --numeric-sort, ряды цифр обрабатываются как числа (, а не отдельные символы ), и сортируются в числовом порядке от наименьшего числа к наибольшему.

Документация не полностью описывает детали, поэтому здесь приведены правила флага -n, полученные экспериментально:

  1. Строки, начинающиеся с цифр, сортируются по числовому значению. (Сначала идут меньшие числа)
  2. Конечные символы в числовых строках не влияют на числовую часть, но конечные символы сортируются в алфавитно-цифровом порядке, если числовая часть одинакова.
  3. Строки, начинающиеся не с числа -, сортируются так, как если бы они были нулевыми, а затем по правилу 2.

Соблюдать:

$ printf %s\\n 2z 111 10 20b 20a aa2 aa10 | sort -n
aa10
aa2
2z
10
20a
20b
111

По правилу 3 строки aa10и aa2обрабатываются как нули и сортируются по оставшимся символам (, включая цифры, которые считаются символами ).

По правилу 2 строки 2z, 20aи 20bобрабатываются как числа, и завершающий символ вступает в силу только тогда, когда числа совпадают.

А по правилу 1 все строки, начинающиеся с цифры, сортируются по числовому значению.

Без флага -nсортировка выполняется посимвольно, где цифровые символы предшествуют буквенным. Соблюдайте:

$ printf %s\\n 2z 111 10 20b 20a aa2 aa10 | sort
10
111
20a
20b
2z
aa10
aa2
1
09.11.2019, 16:49
2 ответа

Мы действительно можем обойтись без cut, если захотим:

while IFS=, read _ _ _ stamp _ ; do
  echo "do something with $stamp here"
done < "$file"

Немного разобрать:

IFS=,временно установить разделитель записей на,

read _ _ _ stamp _сохранить поля 1 -3 и 5 и далее в одноразовой переменной, а поле 4 (записать дату/время )какstamp

< "$file"читаем в исходном файле (это ловится нашей командой read).

Другой способ скрыть эту кошку, заполнив массив каждой строкой (это точно работает в bash, другие оболочки могут не поддерживать это или реализовать по-другому):

while IFS=, read -a line ; do echo "${line[3]}" ; done < "$file"
2
27.01.2020, 23:17

Когда вы перебираете подстановку команд без кавычек $(cat $file), вы перебираете все слова, которые приводят к результату cat $file. Словом будет любое слово, ограниченное пробелом, (пробелом, табуляцией или новой строкой. по умолчанию ). Это означает, что для строки в $file, то есть

883427446627317909,1114259,1573178423,2019-11-08 02:00:23,RD,4.7,0,351442429

у вас будет два слова 883427446627317909,1114259,1573178423,2019-11-08и 02:00:23,RD,4.7,0,351442429(, то есть цикл будет выполняться дважды для этой единственной строки ). Это означает, что вы получите 2019-11-08в первой итерации и 0во второй из этой строки.

Решение состоит в том, не заключать подстановку команды в кавычки, так как это приведет к повторению цикла один раз по всему содержимому файла, которое считывается в $line. Решение не в установке IFSна новую строку, поскольку это неэлегантно(потребовало бы одного вызова cutна каждой итерации ).

Вместо этого разберите нужные данные одним вызовом cutи прочитайте это:

while IFS= read -r datetime; do
    # use "$datetime" here
done < <( cut -d, -f4 "$file" )

При этом используется подстановка процесса для создания входного потока для цикла whileдля чтения. Данные в этом потоке будут состоять из четвертого поля, разделенного запятой -, в файле с именем $file.

В качестве альтернативы, с циклом whileв подоболочке:

cut -d, -f4 "$file" |
while IFS= read -r datetime; do
    # use "$datetime" here
done

С awk,обработка будет чище (, если вам не нужно использовать значение даты/времени в качестве переменной оболочки по какой-либо причине):

awk -F, '{ datetime = $4;... more code here using the datetime variable }' "$file"

Похожие материалы:

2
27.01.2020, 23:17

Теги

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