Есть ли способ полностью удалить поля в awk, чтобы лишние разделители не печатали?
Рассмотрим следующую команду:
gawk -F"\t" "BEGIN{OFS=\"\t\"}{$2=$3=\"\"; print $0}" Input.tsv
Когда я устанавливаю $2 = $3 = "", предполагаемый эффект получает тот же эффект, что и запись:
print $1,$4,$5...$NF
Однако на самом деле происходит то, что я получаю два пустых поля, а дополнительные разделители полей все еще печатаются.
Можно ли фактически удалить $2 и $3?
Примечание. Если это было в Linux в bash
, правильный оператор выше был бы следующим, но Windows не обрабатывает одинарные кавычки в cmd.exe
.
gawk -F'\t' 'BEGIN{OFS="\t"}{$2=$3=""; print $0}' Input.tsv
Ответы
Ответ 1
Это старина, но лакомство.
Как отмечает Джонатан, вы не можете удалять поля в середине, но вы можете заменить их содержимое на содержимое других полей. И вы можете сделать функцию повторного использования для обработки удаления для вас.
$ cat test.awk
function rmcol(col, i) {
for (i=col; i<NF; i++) {
$i=$(i+1)
}
NF--
}
{
rmcol(3)
}
1
$ printf 'one two three four\ntest red green blue\n' | awk -f test.awk
one two four
test red blue
Ответ 2
Вы не можете удалить поля в середине, но вы можете удалить поля в конце, уменьшив NF
.
Итак, вы можете переместить все более поздние поля вниз, чтобы перезаписать $2
и $3
, а затем уменьшить NF
на два, которые стирают последние два поля:
$ echo 1 2 3 4 5 6 7 | awk '{for(i=2; i<NF-1; ++i) $i=$(i+2); NF-=2; print $0}'
1 4 5 6 7
Ответ 3
Если вы просто хотите удалить столбцы, вы можете использовать cut
:
cut -f 1,4- file.txt
Чтобы подражать cut
:
awk -F "\t" '{ for (i=1; i<=NF; i++) if (i != 2 && i != 3) { if (i == NF) printf $i"\n"; else printf $i"\t" } }' file.txt
Similar:
awk -F "\t" '{ delim =""; for (i=1; i<=NF; i++) if (i != 2 && i != 3) { printf delim $i; delim = "\t"; } printf "\n" }' file.txt
НТН
Ответ 4
Одним из способов может быть удаление полей, подобных используемым, и удаление дополнительных пробелов с помощью gsub
:
awk 'BEGIN { FS = "\t" } { $2 = $3 = ""; gsub( /\s+/, "\t" ); print }' input-file
Ответ 5
В дополнение к ответу Suicidal Steve я хотел бы предложить еще одно решение, но с помощью sed вместо awk.
Это кажется более сложным, чем использование разреза, как это предложил Стив. Но это было лучшее решение, потому что sed -i позволяет редактировать на месте.
sed -i 's/\(.*,\).*,.*,\(.*\)/\1\2/' FILENAME
Ответ 6
Единственный способ, с помощью которого я могу сделать это в Awk без использования цикла, - использовать gsub
on $0
для объединения соседних FS
:
$ echo {1..10} | awk '{$2=$3=""; gsub(FS"+",FS); print}'
1 4 5 6 7 8 9 10
Ответ 7
Хорошо, если целью является удаление дополнительных разделителей, вы можете использовать "tr" в Linux. Пример:
$echo "1,2,, 5" | tr -s ','
1,2,5
Ответ 8
echo one two three four five six|awk '{
print $0
is3=$3
$3=""
print $0
print is3
}'
один два три четыре пять шесть
один два четыре пять шесть
три