2017-01-23 3 views
1

У нас есть файл с миллиона записей, как показано ниже:несколько замен, используя сценарий оболочки

123,100F,abc 
456,250F,xyz 

Кроме того, у нас есть некоторое отображение, как показано ниже:

100F > 522 
150F > 523 
200F > 524 
250F > 525 
300F > 526 

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

Выход:

123,522,2017-01-25 
456,525,2017-01-25 
... 

Я не хочу жесткий код, как

sed "s/100F/522/;s/250F/525/;s/\w*/`$date`" input > output 
+0

Вы можете использовать команду 'join' для объединения двух отсортированных файлов. Проверьте его страницу руководства. Поскольку третье поле в вашем выходе является постоянным (текущая дата), это должно работать. – codeforester

+0

Файл данных содержит миллионы записей, но насколько большой файл сопоставлений? – Fred

+0

@Fred: файл сопоставления содержит <20 записей. – user2610

ответ

1

Вы можете попробовать с awk, если файл отображения не столь значителен это хранится в словаре, то обрабатывается большой файл (это можно улучшить, если оба файла отсортированы),

awk -v date="$(date +"%Y-%m-%d")" ' 
    BEGIN{FS=",|[ ]+[>][ ]+"; OFS=","} 
    FNR==NR{d[$1]=$2; next} 
    {print $1,d[$2],date} 
' mapping file_with_million 

или

awk -v date="2017-01-25" ' 
    BEGIN{FS=",|[ ]+[>][ ]+"; OFS=","} 
    FNR==NR{d[$1]=$2; next} 
    {print $1,d[$2],date} 
' mapping file_with_million 

вы получите,

123,522,2017-01-25 
456,525,2017-01-25 
4
$ awk -v date="$(date +"%Y-%m-%d")" ' 
    NR==FNR { map[$1]=$3; next } 
    { print $1, map[$2], date } 
' map FS=, OFS=, file 
123,522,2017-01-23 
456,525,2017-01-23 

или, если вы предпочитаете держать FS и установка ФСУ в скрипте:

$ awk -v date="$(date +"%Y-%m-%d")" ' 
    NR==FNR { map[$1]=$3; next } 
    FNR==1 { FS=OFS=","; $0=$0 } 
    { print $1, map[$2], date } 
' map file 
123,522,2017-01-23 
456,525,2017-01-23 
+0

Спасибо @ Ed Morton: он действительно работает. Не могли бы вы объяснить логику. – user2610

+0

Этот тип работы очень быстрый в awk, я думаю – mug896

+0

@ user2610 Я думаю, что это довольно понятно. Есть ли какая-то его часть, которую вы не понимаете? –

0

Вот решение, используя только «дата» как внешняя ссылка. Обратите внимание, что на производительность, вероятно, повлияет мое назначение даты в цикле (ее можно поставить за пределы цикла, если вам не важно использовать текущую дату с момента запуска скрипта).

#!/bin/bash 

mappings_file="mapping" 
data_file="data" 

# Create a mapping array 
declare -A mappings 
while IFS= read -r line 
do 
    [[ "$line" =~ ^[[:space:]]*([^[:space:]]+)[[:space:]]*\>[[:space:]]*([^[:space:]]+)[[:space:]]*$ ]] || continue 
    key="${BASH_REMATCH[1]}" 
    value="${BASH_REMATCH[2]}" 
    mappings["$key"]="$value" 
done <"$mappings_file" 

# Perform replacement 
while IFS= read -r line 
do 
    # The regex below requires that there be no extra spacing in the data file ; 
    # it could be adjusted to allow it, using the same technique as above 
    [[ "$line" =~ ^(.*),(.*),.*$ ]] || continue 
    # If you trust that the date will not change during execution, 
    # you could put the next assignment outside of the loop 
    date="$(date +"%Y-%m-%d")" 
    key="${BASH_REMATCH[2]}" 
    value="${mappings[$key]}" 
    # If you need to handle missing mappings, do it here before printing 
    printf "%s\n" "${BASH_REMATCH[1]},$value,$date" 
done <"$data_file" 
+0

См. [Why-is-use-a-shell-loop-to-process-text-thought-bad-practice] (http://unix.stackexchange.com/questions/169716/why-is-using-a- shell-loop-to-process-text-thought-bad-practice) по некоторым причинам, чтобы этого не делать. –

+0

Я понимаю, что Bash, возможно, не лучший способ справиться с какой-либо конкретной потребностью (я не говорю, что мое решение здесь правильно). Если вы считаете, что мой код «неправильный» (т. Е. Багги), укажите его. Все это связано с инженерными компромиссами: иногда минимизация внешних зависимостей (для производительности, переносимости или просто знакомство с синтаксисом) превзойдет другие соображения. Еще одно решение, основанное на Bash, - это способность изменять переменные внутри цикла, а в некоторых случаях это необходимо. Знание того, как текст процесса в Bash может быть полезен во многих случаях. – Fred

+0

@EdMorton «Зачем оставлять ответ, если вы не думаете, что это правильный ответ на вопрос?» : потому что я не знаю точной ситуации, в которой находится OP. Пожалуйста, обратите внимание, что я не говорю, что мое предложение, конечно же, неверно. Хорошо знать несколько подходов и быть в состоянии сопоставить преимущества того или другого в каждом конкретном сценарии. – Fred