#bash #awk #sed #grep
#bash #awk #sed #grep
Вопрос:
Я пытаюсь использовать awk, grep или sed, чтобы сгруппировать кучу уличных адресов вместе, сначала упорядочить имя, затем город и сгруппировать их по левому краю по их состоянию.
Вот данные
Mickey Mouse, 1111 Disney Dr., Orlando FL
Minnie Mouse, 1112 Disney Dr., Anaheim CA
Adam Voter, 902 Biscayne Blvd., Miami FL
Zelda Boscso, 4000 State St., Chicago IL
Susie Green, 799 15th St., Indianapolis IN
Tom Furter, 800 N. Walsh St., Milwaukee WI
Dave Ile, 111 W. Illinois Ave., Madison WI
Sam Karter, 1400 E. 57th St., Los Angels CA
Howard Messer, 5957 W. 157th St., Orland Park IL
Ogden Nash, 2800 S. Lake St., Berkeley IL
Penelope Ogden, 1527 W. Aurora Rd., Naperville IL
Harvey Pelican, 800 N. Lake SHore Dr. #134, Michigan City IN
Tawanda Rice, 1027 Belmont Place, West Palm Beach FL
Kendall Smith, 2231 W. 13th St., Madison WI
Byron Trapp, 5 S. Maple Dr., Indianapolis IN
Dominique Daniels, 771 W. 77th Ct., Gary IN
Gandalf Addison, 200 Palm Drive, Jupiter FL
Jenilee Harrison, 511 River Rd., San Francisco CA
Waylon Jetson, 111 Skyway Dr., Green Bay WI
Gollum Zeller, 908 Martin Pl., Tampa FL
Vickie Edison, 14251 W. Central, Milwaukee WI
Milton Callahan, 333 Cordoba Rd., Schamburg IL
Вот как должен выглядеть результат.
CA
Jenilee Harrison, San Francisco
Sam Karter, Los Angeles
Minnie Mouse, Anaheim
FL
Gandalf Addison, Jupiter
Micky Mouse, Orlando
Tawanda Rice, West Palm Beach
Adam Voter, Miami
Gollum Zeller, Tampa
IL
Zelda Bosco, Chicago
Milton Callahan, Schaumburg
Howard Messer, Orland Park
Ogden Nash, Berkeley
Penelope Ogden, Naperville
IN
Dominique Daniels, Gary
Susie Green, Indianapolis
Harvey Pelican, Michigan City
Byron Trapp, Indianapolis
WI
Vickie Edison, Milwaukee
Tom Furter, Milwaukee
Dave Ile, Madison
Waylon Jetson, Green Bay
Kendall Smith, Madison
Вот мой код
awk '{print $NF"|"$1,$2,$5,$6}' amazon.txt | sort -t"|" -k1 | awk -F"" '{print $NF }'
Вот мой вывод.
Jenilee Harrison, Rd., San
Minnie Mouse, Dr., Anaheim
Sam Karter, 57th St.,
Adam Voter, Blvd., Miami
Gandalf Addison, Drive, Jupiter
Что я делаю не так? Обратите внимание, что в названиях некоторых городов есть 1 или 2 слова.
Комментарии:
1. Используйте массив, ключами которого являются состояния.
2. Вам нужно использовать
,
в качестве разделителя полей. Затем вам нужно разделить последнее поле, используя пробел, чтобы разделить город и штат.3. @Barmar Как создать массив в Bash, когда существует переменное количество состояний?
4. Массив должен быть in
awk
, а неbash
.a[state] = a[state] "n" $1 ", " city
5. Обязательно ли это делать в Bash? Почему бы просто не сделать это на Python? Более поддерживаемый, тестируемый, расширяемый и т. Д.?
Ответ №1:
Не могли бы вы, пожалуйста, попробовать следующее, написанное и протестированное с показанными примерами в GNU awk
.
awk '
BEGIN{ FS=OFS=", " }
{
sub(/ $/,"")
match($NF,/.* /)
city=substr($NF,RSTART,RLENGTH)
sub(/ $/,"",city)
district=substr($NF,RSTART RLENGTH)
cityArr[district]=(cityArr[district]?cityArr[district] ORS:"")($1 OFS city)
}
END{
for(i in cityArr){
print i ORS cityArr[i]
}
}' Input_file
Объяснение: добавление подробного объяснения выше.
awk ' ##Starting awk program from here.
BEGIN{ FS=OFS=", " } ##Setting field separator and output field separator as comma space here.
{
sub(/ $/,"") ##Substitute spaces at last of line with NULL here, to remove them from output.
match($NF,/.* /) ##Using match function to match everything till last occurrence of spaces in last field.
city=substr($NF,RSTART,RLENGTH) ##Creating city variable which has sub string starting from RSTART to RLENGTH(where RSTART and RLENGTH are default variables of awk)
sub(/ $/,"",city) ##Substituting last occurring spaces in variable city.
district=substr($NF,RSTART RLENGTH) ##Creating variable district, which has the last value in line.
cityArr[district]=(cityArr[district]?cityArr[district] ORS:"")($1 OFS city) ##Creating cityArr(array) which has index
##as district and keep appending 1st field and value of city in this array with same indexes here.
}
END{ ##Starting END block of this program from here.
for(i in cityArr){ ##Traversing through cityArr here.
print i ORS cityArr[i] ##Printing index with new line and value of cityArr here.
}
}' Input_file ##Mentioning Input_file name here.
Также в ваших показанных примерах есть пробелы в конце строки, чтобы удалить их, я позаботился об этом тоже в этом решении.
РЕДАКТИРОВАТЬ: для печати новой строки после каждого значения района просто добавлена логика в приведенном выше решении.
awk '
BEGIN{ FS=OFS=", " }
{
sub(/ $/,"")
match($NF,/.* /)
city=substr($NF,RSTART,RLENGTH)
sub(/ $/,"",city)
district=substr($NF,RSTART RLENGTH)
cityArr[district]=(cityArr[district]?cityArr[district] ORS:"")($1 OFS city)
}
END{
for(i in cityArr){
if( count>1){ print "" }
print i ORS cityArr[i]
}
}' Input_file
Комментарии:
1. Работает как шарм! Единственная небольшая проблема заключается в том, что между последним вводом состояния и следующим начальным состоянием должна быть новая строка. Это небольшая проблема, которую даже я, вероятно, мог бы исправить.
2. @Peabodyjr., добро пожаловать. Вероятно, вы могли бы изменить свой
cityArr[i]
END
блок in этого кода наcityArr[i] ORS
, и он должен напечатать новую строку, но единственное, что вы получите, наконец, на выходе, приветствия.3. @Peabodyjr., хорошо, я добавил решение для редактирования, пожалуйста, проверьте его один раз, приветствия.
Ответ №2:
Это может сработать для вас (GNU sed):
sed -E 's/(.*),.*,(.*) (SS).*/3n1,2/ # reduce and re-arrange record
H # append to hold space
x # swap to hold space
s/(n..)(n.*)1(n.*)/132/ # group by state
x # swap back to pattern space
$!d # delete all but last
x # swap to hold space again
s/.//' file # remove starting newline and print
Чтобы отформатировать файл в отсортированном порядке и через пробел между состояниями, используйте:
sed -E 's/(.*),.*,(.*) (SS).*/3 1,2/' file |
sort -k1,1 -k3,4r |
sed -E 's/(..) (.*)/1n2/
H
x
s/(n..)(n.*)1(n.*)/132/
x
$!d
x
s/n..n/namp;/g
s/..//'