Предполагая, что вы в настоящее время вызываете свою программу с двумя аргументами как 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
Немного неудобно, но я думаю, что это работает.
Пакет csvkit
Python содержит инструменты командной строки для работы с 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 )
Выражение sed
1!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
Мне не удалось сделать это с 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
При работе с CSV-файлами основная проблема, с которой вы сталкиваетесь, заключается в том, что ваш разделитель столбцов может находиться в самом значении столбца, если столбец имеет тип string и строка заключена в (двойные )кавычки..
Итак, следующая команда:
sed -r 's/^(([^,]*,){6})([^\.,]*)[^,]*(,.*)$/\1\3\4/g'
будет работать, но только если у вас нет запятой в текстовой строке. Если вы имеете дело с таким случаем, то необходим такой инструмент, как тот, который был предложен предыдущим автором.
Я попытался сделать это, используя самое длинное регулярное выражение от начала строки до последних двойных кавычек, использовал следующее поле как есть, сохранил целые цифры до десятичной дроби и удалил .0
. Вот решение
sed 's/\(.*\",[^,]*,[[:digit:]]*\)\.0\(.*\)/\1\2/'
Простой подход 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
С инструментами 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
.