В настоящее время у меня есть несколько файлов с миллионами строк, которые выглядят следующим образом:
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15
Номера 565 и 564 являются идентификаторами, и я извлек все уникальные идентификаторы из разных файлов и объединил их в один файл, выглядящий следующим образом:
565
564
182
982
Далее, я хочу провести следующее преобразование чисел в исходных файлах:
565 -> 1
564 -> 2
182 -> 3
982 -> 4
, так что исходные файлы будут выглядеть так:
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
Я знаю, как применять одно преобразование с помощью sed, но есть ли способы указать способ преобразования в текстовом файле и использовать сценарий оболочки для примените его к исходным файлам?
Спасибо.
Если вы хотите монотонно наращивать первое поле, вам не нужно использовать дополнительный файл для сопоставления или первого поля, просто используйте awk, чтобы установить первое поле в качестве номера строки (записи):
awk '{$1=NR} 1' file.txt
Он перестроит всю запись с пространством в качестве нового разделителя полей, но в этом случае я считаю, что мы в безопасности, поскольку поля разделены пробелами.
Теперь, вот способы решения вашей проблемы, когда у вас есть дополнительный файл, скажем, id.txt с первыми полями:
Вам было бы лучше использовать то, что может понять номер строки и отслеживать их, например awk:
awk 'NR==FNR {a[$0]=NR; next} {$1=a[$1]} 1' id.txt file.txt
Предполагая, что id.txt содержит только извлеченные первые столбцы, а file.txt - основной файл NR==FNR {a[$0]=NR; next} сохраняет каждую запись файла id.txt в качестве ключа ассоциативного массива a со значением, являющимся соответствующим номером строки. next не гарантирует, что дальнейшая обработка записей id.txt {$1=a[$1]} устанавливает первое поле в значение соответствующего элемента массива; обратите внимание, что в этом есть предостережение по восстановлению всей записи с пространством в качестве разделителя, но я предполагаю, что в этом случае мы можем использовать эту краткость. 1 является просто заполнителем для интерпретации true, так что вся запись печатается впоследствии Если вы чувствуете себя странно, вы можете использовать некоторые стандартные инструменты * nix, с помощью из подстановки процесса (<()) из bash и paste наконец:
paste -d' ' <(nl id.txt | cut -f1) <(cut -d' ' -f2- file.txt)
, предполагая, что id.txt содержит только извлеченные первые столбцы, а file.txt является основным файлом Предполагая, что id.txt содержит только извлеченные первые столбцы, а file.txt - основной файл
cut -d' ' -f2- file.txt получает все поля но первый
% cat file.txt
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15
182 10 12 23 18 17 25
892 1 7 12 13 16 18 40 29 15
% awk '{$1=NR} 1' file.txt
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
3 10 12 23 18 17 25
4 1 7 12 13 16 18 40 29 15
% cat id.txt
565
564
182
892
% awk 'NR==FNR {a[$0]=NR; next} {$1=a[$1]} 1' id.txt file.txt
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
3 10 12 23 18 17 25
4 1 7 12 13 16 18 40 29 15
% paste -d' ' <(nl id.txt | cut -f1) <(cut -d' ' -f2- file.txt)
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
3 10 12 23 18 17 25
4 1 7 12 13 16 18 40 29 15
Если вы хотите монотонно наращивать первое поле, вам не нужно использовать дополнительный файл для сопоставления или первого поля, просто используйте awk, чтобы установить первое поле в качестве номера строки (записи):
awk '{$1=NR} 1' file.txt
Он перестроит всю запись с пространством в качестве нового разделителя полей, но в этом случае я считаю, что мы в безопасности, поскольку поля разделены пробелами.
Теперь, вот способы решения вашей проблемы, когда у вас есть дополнительный файл, скажем, id.txt с первыми полями:
Вам было бы лучше использовать то, что может понять номер строки и отслеживать их, например awk:
awk 'NR==FNR {a[$0]=NR; next} {$1=a[$1]} 1' id.txt file.txt
Предполагая, что id.txt содержит только извлеченные первые столбцы, а file.txt - основной файл NR==FNR {a[$0]=NR; next} сохраняет каждую запись файла id.txt в качестве ключа ассоциативного массива a со значением, являющимся соответствующим номером строки. next не гарантирует, что дальнейшая обработка записей id.txt {$1=a[$1]} устанавливает первое поле в значение соответствующего элемента массива; обратите внимание, что в этом есть предостережение по восстановлению всей записи с пространством в качестве разделителя, но я предполагаю, что в этом случае мы можем использовать эту краткость. 1 является просто заполнителем для интерпретации true, так что вся запись печатается впоследствии Если вы чувствуете себя странно, вы можете использовать некоторые стандартные инструменты * nix, с помощью из подстановки процесса (<()) из bash и paste наконец:
paste -d' ' <(nl id.txt | cut -f1) <(cut -d' ' -f2- file.txt)
, предполагая, что id.txt содержит только извлеченные первые столбцы, а file.txt является основным файлом Предполагая, что id.txt содержит только извлеченные первые столбцы, а file.txt - основной файл
cut -d' ' -f2- file.txt получает все поля но первый
% cat file.txt
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15
182 10 12 23 18 17 25
892 1 7 12 13 16 18 40 29 15
% awk '{$1=NR} 1' file.txt
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
3 10 12 23 18 17 25
4 1 7 12 13 16 18 40 29 15
% cat id.txt
565
564
182
892
% awk 'NR==FNR {a[$0]=NR; next} {$1=a[$1]} 1' id.txt file.txt
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
3 10 12 23 18 17 25
4 1 7 12 13 16 18 40 29 15
% paste -d' ' <(nl id.txt | cut -f1) <(cut -d' ' -f2- file.txt)
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
3 10 12 23 18 17 25
4 1 7 12 13 16 18 40 29 15
Если вы хотите монотонно наращивать первое поле, вам не нужно использовать дополнительный файл для сопоставления или первого поля, просто используйте awk, чтобы установить первое поле в качестве номера строки (записи):
awk '{$1=NR} 1' file.txt
Он перестроит всю запись с пространством в качестве нового разделителя полей, но в этом случае я считаю, что мы в безопасности, поскольку поля разделены пробелами.
Теперь, вот способы решения вашей проблемы, когда у вас есть дополнительный файл, скажем, id.txt с первыми полями:
Вам было бы лучше использовать то, что может понять номер строки и отслеживать их, например awk:
awk 'NR==FNR {a[$0]=NR; next} {$1=a[$1]} 1' id.txt file.txt
Предполагая, что id.txt содержит только извлеченные первые столбцы, а file.txt - основной файл NR==FNR {a[$0]=NR; next} сохраняет каждую запись файла id.txt в качестве ключа ассоциативного массива a со значением, являющимся соответствующим номером строки. next не гарантирует, что дальнейшая обработка записей id.txt {$1=a[$1]} устанавливает первое поле в значение соответствующего элемента массива; обратите внимание, что в этом есть предостережение по восстановлению всей записи с пространством в качестве разделителя, но я предполагаю, что в этом случае мы можем использовать эту краткость. 1 является просто заполнителем для интерпретации true, так что вся запись печатается впоследствии Если вы чувствуете себя странно, вы можете использовать некоторые стандартные инструменты * nix, с помощью из подстановки процесса (<()) из bash и paste наконец:
paste -d' ' <(nl id.txt | cut -f1) <(cut -d' ' -f2- file.txt)
, предполагая, что id.txt содержит только извлеченные первые столбцы, а file.txt является основным файлом Предполагая, что id.txt содержит только извлеченные первые столбцы, а file.txt - основной файл
cut -d' ' -f2- file.txt получает все поля но первый
% cat file.txt
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15
182 10 12 23 18 17 25
892 1 7 12 13 16 18 40 29 15
% awk '{$1=NR} 1' file.txt
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
3 10 12 23 18 17 25
4 1 7 12 13 16 18 40 29 15
% cat id.txt
565
564
182
892
% awk 'NR==FNR {a[$0]=NR; next} {$1=a[$1]} 1' id.txt file.txt
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
3 10 12 23 18 17 25
4 1 7 12 13 16 18 40 29 15
% paste -d' ' <(nl id.txt | cut -f1) <(cut -d' ' -f2- file.txt)
1 0 10 12 23 18 17 25
2 1 7 12 13 16 18 40 29 15
3 10 12 23 18 17 25
4 1 7 12 13 16 18 40 29 15
awk 'BEGIN {OFS=""} {print "s/^", $0, "/", ++count, "/"}' > pattern.sed ids.txt
Он будет читать ваш файл «ids» и создает список идентификаторов для поиска и замены с помощью sed.
$ cat pattern.sed
s/^564/1/
s/^565/2/
...
Если ваши идентификаторы не уникальны, вы можете использовать:
sort ids.txt | uniq | awk 'BEGIN {OFS=""} {print "s/^", $0, "/", ++count, "/"}' > pattern.sed
, чтобы сделать его более эффективным, затем запустите:
$ sed -i.bk -f pattern.sed file
$ cat file
2 0 10 12 23 18 17 25
1 1 7 12 13 16 18 40 29 15
1 1 7 12 13 16 18 40 29 11111
1 1 7 12 13 16 18 40 29 15555
2 0 10 12 23 18 17 2555
...
Если вы хотите сортировать конечный файл, используйте sort -k1,1 file > file.sorted.
awk 'BEGIN {OFS=""} {print "s/^", $0, "/", ++count, "/"}' > pattern.sed ids.txt
Он будет читать ваш файл «ids» и создает список идентификаторов для поиска и замены с помощью sed.
$ cat pattern.sed
s/^564/1/
s/^565/2/
...
Если ваши идентификаторы не уникальны, вы можете использовать:
sort ids.txt | uniq | awk 'BEGIN {OFS=""} {print "s/^", $0, "/", ++count, "/"}' > pattern.sed
, чтобы сделать его более эффективным, затем запустите:
$ sed -i.bk -f pattern.sed file
$ cat file
2 0 10 12 23 18 17 25
1 1 7 12 13 16 18 40 29 15
1 1 7 12 13 16 18 40 29 11111
1 1 7 12 13 16 18 40 29 15555
2 0 10 12 23 18 17 2555
...
Если вы хотите сортировать конечный файл, используйте sort -k1,1 file > file.sorted.
awk 'BEGIN {OFS=""} {print "s/^", $0, "/", ++count, "/"}' > pattern.sed ids.txt
Он будет читать ваш файл «ids» и создает список идентификаторов для поиска и замены с помощью sed.
$ cat pattern.sed
s/^564/1/
s/^565/2/
...
Если ваши идентификаторы не уникальны, вы можете использовать:
sort ids.txt | uniq | awk 'BEGIN {OFS=""} {print "s/^", $0, "/", ++count, "/"}' > pattern.sed
, чтобы сделать его более эффективным, затем запустите:
$ sed -i.bk -f pattern.sed file
$ cat file
2 0 10 12 23 18 17 25
1 1 7 12 13 16 18 40 29 15
1 1 7 12 13 16 18 40 29 11111
1 1 7 12 13 16 18 40 29 15555
2 0 10 12 23 18 17 2555
...
Если вы хотите сортировать конечный файл, используйте sort -k1,1 file > file.sorted.