sed :обрезать десятичные знаки в столбце CSV-файла

Предполагая, что вы в настоящее время вызываете свою программу с двумя аргументами как cmd input-file output-file, вы можете просто написать сценарий-оболочку как:

#!/bin/sh
for file; do 
    output="${file%.txt}"-s.txt
    cmd "$file" "$output" &
done

Затем вызовите скрипт, указав несколько входных данных в качестве аргументов. Это решение предполагает, что все ваши входные файлы имеют .txtсуффикс (ну, на самом деле это не предполагается, но имена выходных файлов будут неверными, если они не ). Обратите внимание, что это потенциально перезапишет существующие выходные файлы; добавьте немного логики для проверки предыдущего существования, если вы беспокоитесь об этом. Вероятно, безопаснее создать каталог и поместить все ваши выходные файлы в новый каталог, чтобы избежать этой проблемы. Или, если вы хотите прочитать имена файлов из ввода :(, например, вы можете вызвать скрипт с помощью < my-file-full-of-input-files-one-per-line./my-script), напишите его как:

#!/bin/sh
while read file; do
    output="${file%.txt}"-s.txt
    cmd "$file" "$output" &
done
0
03.05.2021, 00:13
6 ответов

Немного неудобно, но я думаю, что это работает.

Пакет csvkitPython содержит инструменты командной строки для работы с CSV-файлами. Среди них csvcut, которая работает как стандартная команда cut, но поддерживает CSV, что означает, что она позволяет использовать поля, которые могут содержать встроенные разделители полей и новые строки, если они правильно заключены в кавычки.

С помощью csvcutмы можем вырезать столбец, который мы хотим изменить, изменить его, а затем вставить обратно. Я использую paste, чтобы снова собрать поля вместе с запятой в качестве разделителя.. Утилита pasteполучает три входных потока, соответствующих первым нескольким полям (, немодифицированным ), полю, которое мы хотим исправить (, модифицированному с помощью простого sedскрипта ), и последним нескольким поля (без изменений ).

paste -d, \
    <( csvcut -c -5  file.csv ) \
    <( csvcut -c  6  file.csv | sed '1!s/\..*//' ) \
    <( csvcut -c  7- file.csv )

Выражение sed1!s/\..*//удаляет точку и все после нее во всех строках, кроме первой.

Это немного неэффективно, так как весь входной файл читается три раза.

Результат:

PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Ticket,Fare,Cabin,Embarked
343,No,2,"Collander, Mr. Erik Gustaf",male,28,0,0,248740,13.0,,S
76,No,3,"Moen, Mr. Sigurd Hansen",male,25,0,0,348123,7.65,F G73,S
3
28.07.2021, 11:35

Мне не удалось сделать это с sed, потому что использование запятых в качестве разделителя, а также запятая в поле имени, не являющаяся разделителем, усложняли задачу, поэтому я использовал awkс gsub. ] опция:

awk -F ',' 'NR==1; NR>1{gsub("\.0","",$7);print} ' OFS="," file

Это несколько запутанно, учитывая обстоятельства, но он устанавливает запятую в качестве разделителя, печатает первую строку, а затем в любой строке после первой строки заменяет .0ничем в 7-м поле в качестве запятой в имени эффективно делает возраст 7-м полем,а затем снова устанавливает разделитель выходных полей в виде запятой, а затем печатает:

PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Ticket,Fare,Cabin,Embarked
343,No,2,"Collander, Mr. Erik Gustaf",male,28,0,0,248740,13.0,,S
76,No,3,"Moen, Mr. Sigurd Hansen",male,25,0,0,348123,7.65,F G73,S
1
28.07.2021, 11:35

При работе с CSV-файлами основная проблема, с которой вы сталкиваетесь, заключается в том, что ваш разделитель столбцов может находиться в самом значении столбца, если столбец имеет тип string и строка заключена в (двойные )кавычки..

Итак, следующая команда:

sed -r 's/^(([^,]*,){6})([^\.,]*)[^,]*(,.*)$/\1\3\4/g'

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

0
28.07.2021, 11:35

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

sed 's/\(.*\",[^,]*,[[:digit:]]*\)\.0\(.*\)/\1\2/'
0
28.07.2021, 11:35

Простой подход awk может состоять в том, чтобы получить поле age, смотрящее с конца, потому что с этого конца поля не имеют разделителей внутри:

awk -F, -v OFS=, '
  NR>1{$(NF-6) = int($(NF-6))}1
' file

Используя sed с расширенным регулярным выражением -r, мы считать поля с конца

sed -r '
  s/\.0((,[^,]*){6})$/\1/
' file

Выход:

PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Ticket,Fare,Cabin,Embarked
343,No,2,"Collander, Mr. Erik Gustaf",male,28,0,0,248740,13.0,,S
76,No,3,"Moen, Mr. Sigurd Hansen",male,25,0,0,348123,7.65,F G73,S

0
28.07.2021, 11:35

С инструментами csvkit:

csvjoin -I -c PassengerId <(csvcut -c -5 file.csv) <(csvcut -c 1,6 file.csv | awk '{sub(/[.][0-9]+/, ""); print}') <(csvcut -c 1,7- file.csv)

Для ознакомления с csvkitи csvcutсм. другой ответ .

csvcutберет поля из CSV-файлов с аргументом -c HeaderNameили -c HeaderNumber. -Cделает прямо противоположное.

В нашем файле используйте вот так :csvcut -c 6 file.csvилиcsvcut -c Age file.csv

csvcut -c 1,6 file.csvзанимает первое и шестое поле файла данных. Вывод этой команды передается на awk '{sub(/[.][0-9]+/, ""); print}')для удаления точки и цифр после этой точки. Точка .используется в наборе символов [], потому что в выражении регулярного выражения без этого она соответствовала бы любому одиночному символу, кроме новой строки.

csvcut -c -5 file.csv— это сокращение от csvcut -c 1-5 file.csv. Это означает, что мы хотим взять первые пять полей. Точно так же csvcut -c 7- file.csvберет поля с седьмого поля в конец.

csvjoinможет объединить три потока по столбцам с аргументом -c. В этом случае столбец, который мы использовали для объединения, — PassengerId. Чтобы использовать PassengerIdдля объединения, мы брали первое поле в каждом потоке.

Мы использовали -Iили --no-inference, потому что без этого аргумента строка «Нет» или нули были бы заменены на False.

0
28.07.2021, 11:35

Теги

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