каждый.
У меня есть файл с именами в формате:
Name Name Surname Surname
Это файл с именами
Nikola KAZIKOVA
Pavel MILAN GAZDIK
Nikolas Martin STRUP
Nikola GAZDIK
Nikola ČERNÁ
Nikola Martina ČERNÁ
Я пытаюсь создать сценарий, который печатает ряд вхождений рядом с каждым именем. Однако я не могу понять, как их считать.
Это мой код, я могу загрузить текст в массив, но не могу понять, как считать имена.
#!/bin/bash
file=$1
if [[ -z $1 ]]
then echo "ERROR: FILE NOT FOUND"
exit
fi
# Read the file in parameter and fill the array named "array"
getArray() {
array=() # Create array
while IFS= read -r line # Read a line
do
array+=("$line") # Append line to the array
done < "$1"
}
# Print the file (print each element of the array)
getArray $file
for e in "${array[@]}"
do
IFS=' ' read -ra arr <<< "$e"
echo "${arr[0]}" | grep -o "${arr[0]}"
done
Это результат, которого я пытаюсь достичь
[4] Nikola KAZIKOVA
[1] Pavel MILAN GAZDIK
[1] Nikolas Martin STRUP
[4] Nikola GAZDIK
[4] Nikola ČERNÁ
[4] Nikola Martina ČERNÁ
🤔 А знаете ли вы, что...
Bash поддерживает создание функций для группировки команд и повторного использования кода.
Один вариант:
while read -r f l ; do echo "[$(grep -w -c $f d.dat)] $f $l" ; done <d.dat
Выход:
[4] Nikola KAZIKOVA
[1] Pavel MILAN GAZDIK
[1] Nikolas Martin STRUP
[4] Nikola GAZDIK
[4] Nikola ČERNÁ
[4] Nikola Martina ČERNÁ
Обратите внимание, что это не очень эффективно из-за grep
внутри цикла. Если ваш файл большой, вы можете использовать альтернативные инструменты, такие как. awk
или python
.
awk
альтернатива;
awk 'NR==FNR{A[$1]++}NR>FNR{for(i in A) {if (i==$1){printf "[%s] %s\n", A[i], $0}}}' d.dat d.dat
Выход:
[4] Nikola KAZIKOVA
[1] Pavel MILAN GAZDIK
[1] Nikolas Martin STRUP
[4] Nikola GAZDIK
[4] Nikola ČERNÁ
[4] Nikola Martina ČERNÁ
с вашими показанными образцами, пожалуйста, попробуйте следовать коду awk
.
awk '
{
value[FNR]=$0
occur[$1]++
}
END{
for(i=1;i<=FNR;i++){
split(value[i],arr,FS)
print "["occur[arr[1]] "] " value[i]
}
}
' Input_file
Объяснение: добавлено подробное объяснение приведенного выше кода.
awk ' ##Starting awk program from here.
{
value[FNR]=$0 ##Creating array named value which has index as current line number and value as currnet line value.
occur[$1]++ ##Creating array named occur with index of 1st field and keep adding same index element here.
}
END{ ##Starting END block of this program from here.
for(i=1;i<=FNR;i++){ ##Using for loop till value of FNR here.
split(value[i],arr,FS) ##Splitting value[i] into arr with separator as space.
print "["occur[arr[1]] "] " value[i] ##Printing values as per requirement here.
}
}
' Input_file ##Mentioning Input_file name here.
Это может сработать для вас (GNU sed, sort, uniq):
sed 's/ .*//' file |
sort |
uniq -c |
sed -nE 's/^\s*(\S+) (\S+)/s#^\2\\b#[\1] \&#/p' |
sed -f - file
Удалите все, кроме имени, из каждой строки.
Рассортируйте имена.
Используя uniq
, подсчитайте количество вхождений каждого имени.
Превратите приведенный выше результат в сценарий sed, который добавляет к каждому имени префикс в формате [n]
.
Примените приведенный выше сценарий sed к исходному файлу.
Если ввод/данные не слишком большие/большие, чистое решение bash будет выглядеть примерно так:
#!/usr/bin/env bash
declare -A Name
declare -a full_name names
while read -ra names; do
full_name+=("${names[*]}")
((Name[${names[0]}]++))
done < file.txt
for name in "${!full_name[@]}"; do
first_name = "${full_name[$name]%% *}"
for key in "${!Name[@]}"; do
[[ "$first_name" == "$key" ]] &&
printf '[%d] %s\n' "${Name[$key]}" "${full_name[$name]}" &&
break
done
done