При обработке входных файлов копирование / обновление и переименование допустимый подход?

Это:

sed 's/KN\d+.1/KN\d+v1/g' file.txt

ничего не делает, потому что ваш sed, скорее всего, не поддерживает \ d (я думаю, что это из Perl), поэтому шаблон ничего не соответствует. Вы можете сослаться на это: Почему мое регулярное выражение работает в X, но не в Y?

В любом случае оно не будет работать так, как вы хотите, поскольку \ d просто экранирует d в заменяемой части, а + не является особенным, поэтому ваши числа заменяются.

В Perl вам может понадобиться что-то вроде этого:

perl -pe 's/(KN\d+)\.1/$1v1/'  file.txt 

Где $ 1 расширяется до первой группы в скобках, а точка экранируется, поскольку это регулярное выражение для любого символа . Или

perl -pe 's/KN\d+\K\.1/v1/'  file.txt 

Где \ K уничтожает предыдущую часть совпадения, так что она не заменяется.

Хотя, если вам не важен контекст точки, используйте tr . (или tr /// на Perl).

2
03.02.2017, 22:57
2 ответа

Оставить исходные файлы нетронутыми и выполнить обработку копий - очень хорошая идея. Вам следует пойти дальше и не использовать повторно промежуточные файлы. Если вы повторно используете промежуточные файлы, и процесс будет прерван, у вас не будет возможности узнать, в какой момент он был прерван.

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

Все инструменты обработки текста, которые вы используете, могут читать из стандартного ввода и записывать в стандартный вывод. Вы можете объединить их, поместив трубку между выходом одного инструмента и входом следующего инструмента. Таким образом, вам не нужно так много промежуточных файлов - фактически, в этом случае вам не нужен какой-либо промежуточный файл. Каналы - это фундаментальная особенность дизайна Unix.

Еще один совет по программированию оболочки: всегда заключайте в двойные кавычки расширения переменных , т. Е. $ foo .

#!/bin/bash                                                                                                      

preprocess_csv () {
  <"$1" \
  tr -d '\r' |
  awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' >"${1%.csv}.clean"
}

preprocess_csv "$1"
preprocess_csv "$2"

do_stuff_with_preprocessed_file "${1%.csv}.clean" "${2%.csv}.clean" >global_output

Я использовал расширение параметра конструкцию $ {1% .csv} для преобразования, например, foo.csv в foo , так что выходной файл этого преобразования будет foo.clean .

Этот сценарий проще, чем был у вас, но его все еще можно улучшить. Для описания цепочки команд обработки файлов существуют инструменты лучше, чем сценарии оболочки: инструменты автоматизации сборки , такие как классический make . См. Выполнить список команд с контрольной точкой? для ознакомления с аналогичным вариантом использования. Вот как можно выразить вашу трансформацию с помощью make. Назовите этот файл Makefile . Обратите внимание, что там, где в приведенных ниже строках имеется отступ в 8 пробелов, вам нужно заменить 8 пробелов символом табуляции, это особенность make.

default: global_output

%.clean: %.csv
        <'$<' tr -d '\r' | awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' >'$@'

global_output: input1.clean input2.clean
        do_stuff_with_preprocessed_files input1.clean input2.clean >$@

$ < в команде обозначает зависимость (файл справа от target: dependency выше), а $ @ обозначает цель. Если в make-файле выше вы запустите команду make global_output (или просто make , благодаря строке default: в начале), она запустит команду преобразования для создания файлов .clean (файлы .csv должны уже существовать), а затем он запустит do_stuff_with_preprocessed_files для создания global_output .

Этот make-файл хрупкий, потому что он оставляет частично обработанные файлы, если его прервать на полпути.Чтобы исправить это, используйте временные файлы в каждом правиле, как описано в Выполнить список команд с контрольной точкой? .

default: global_output

%.clean: %.csv
        <'$<' tr -d '\r' | awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' >'$@.tmp'
        mv '$@.tmp' '$@'

global_output: input1.clean input2.clean
        do_stuff_with_preprocessed_files input1.clean input2.clean >'$@.tmp'
        mv '$@.tmp' '$@'
3
27.01.2020, 21:52

Это достигается через канал ( | ). Есть много хороших руководств, таких как этот .

#!/bin/bash
[[ -z $1 ]] && echo 'We need input file a' && exit 1;
[[ -z $2 ]] && echo 'We need input file b' && exit 1;  

A_CSV=$1;  
B_CSV=$2;  

A_FILE="$A_CSV.tmp";  
B_FILE="$B_CSV.tmp";  

[ -f $A_FILE ]] && rm $A_FILE;
[[ -f $B_FILE ]] && rm $B_FILE;

tr -d "\r" < $A_CSV | awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' > $A_FILE
tr -d "\r" < $B_CSV | awk '{ if(NR == 1) sub(/^\xef\xbb\xbf/,""); print }' > $B_FILE

Я бы лично создал функцию для работы с одной операцией, поскольку вы делаете одно и то же с обоими файлами. rm -f $ A_FILE $ B_FILE , на мой взгляд, тоже выглядел бы лучше.

4
27.01.2020, 21:52

Теги

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