Замена строк в файле на основе списка строк и списка соответствующих замен

Извините, принятый ответ - плохая информация по нескольким фронтам.

/proc/sys/kernel/pid_max не имеет ничего общего с максимальным количеством процессов, которые могут быть запущены в любой момент времени. Это, по сути, максимальный числовой идентификатор процесса, который может быть присвоен ядром.

В ядре Linux процесс и поток — это одно и то же. Они обрабатываются таким же образом ядром. Они оба занимают место в task_struct структуре данных. Поток, по общепринятой терминологии, в Linux — это процесс, который совместно использует ресурсы с другим процессом (они также будут совместно использовать идентификатор группы потоков). Поток в ядре Linux в значительной степени является концептуальной конструкцией для планировщика.

Теперь, когда вы понимаете, что ядро в значительной степени не различает поток и процесс, должно иметь больше смысла, что /proc/sys/kernel/threads-max на самом деле является максимальным количеством элементов, содержащихся в структуре данных task_struct. Это структура данных, содержащая список процессов или, как их можно назвать, задач.

ulimit — это, как следует из названия, ограничение на пользователя. Флаг -u определяется как «Максимальное количество процессов, доступных одному пользователю». Элемент task_struct содержит идентификатор uID пользователя, создавшего задачу. A пер-Счетчик uid поддерживается и увеличивается/уме умещается каждый раз, когда задача добавляется/удаляется из task_struct. Таким образом, ulimit -u указывает на максимальное количество элементов (процессов), которые один конкретный пользователь может иметь в пределах task_struct в любой момент времени.

Я надеюсь, что это прояснит ситуацию.

5
20.03.2016, 20:25
5 ответов

Решение, которое я создал, не очень короткое, но достаточно простое, чтобы его можно было легко читать. если ваша задача не состояла в том, чтобы сделать все это с помощью sed ...?

 #!/usr/bin/bash

 cp A.txt D.txt

 x=1
 length=$(wc -l B.txt | sed 's/\ .*//g')

 until [ $x -eq $length ]; do

    Bx=$(awk "NR==$x" B.txt)
    Cx=$(awk "NR==$x" C.txt)

    sed -i "s/$Bx/$Cx/g" D.txt

    x=$(($x+1))

 done

 rm -f ./sed*

обратите внимание, что этот сценарий создает тонну ненужных файлов, если B.txt длиннее C.txt и, возможно, наоборот (не тестировал это так далеко)

-1
27.01.2020, 20:35

В простом примере, который вы показываете, когда каждое из целевых слов появляется в файле только один раз, вы можете просто сделать:

$ paste fileB fileC | while read a b; do sed -i "s/$a/$b/" fileA; done
$ cat fileA
Hello John, how is your wife? where is grandpa? 

Команда paste распечатает данные из обоих файлов вместе:

$ paste fileB fileC
Peter   John
dad wife
mom grandpa

Мы передаем это через простой цикл при чтении , который будет перебирать каждую строку, сохраняя значение из fileB как $ a и значение из fileC как $ b . Затем команда sed заменит первое вхождение $ a на $ b . Это повторяется трижды.

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

Итак, если у вас есть файлы большего размера, вам может потребоваться что-то вроде этого:

paste fileB fileC | 
    perl -lane '$words{$F[0]}=$F[1]} 
        END{open(A,"fileA"); while(<A>){s/$_/$words{$_}/ for keys %words; print}'
1
27.01.2020, 20:35

Самый простой способ сделать это с помощью sed - обработать эти два списка и превратить их в файл сценария , например

s/line1-from-fileB/line1-from-fileC/g
s/line2-from-fileB/line2-from-fileC/g
....................................
s/lineN-from-fileB/lineN-from-fileC/g

, который затем выполнит sed , редактируя fileA . Правильный способ - сначала обработать LHS / RHS и исключить любые специальные символы, которые могут появиться в этих строках, а затем присоединиться к LHS ] и RHS , добавляя s , разделители / и g (например, с пастой ) и результат для sed :

paste -ds///g /dev/null /dev/null \
<(sed 's|[[\.*^$/]|\\&|g' fileB) <(sed 's|[\&/]|\\&|g' fileC) \
/dev/null /dev/null | sed -f - fileA

Итак, вот оно: одна paste и три sed , которые будут обрабатывать каждый файл только один раз, независимо от количества линий.
Предполагается, что ваша оболочка поддерживает подстановку процессов и что ваш sed может читать файл сценария из stdin . Кроме того, он не редактируется на месте (я пропустил переключатель -i , поскольку он не поддерживается всеми sed s)

10
27.01.2020, 20:35

Это может помочь решить вашу проблему. (См .: https://unix.stackexchange.com/questions/283017/awk-command-i-want-to-compare-two-rows -in-two-files-and-update-the-second-file-i )

Source.txt имеет следующие две строки:

OldString
NewString

Перед выполнением команды Target.txt содержит следующие строки:

OldString ==> NewString
This is Target File containing OldString now.
OldString is to be replaced.
NewString won't get impacted.

Use :

awk -v lookupStr=`awk 'NR==1' Source.txt` -v replacementStr=`awk 'NR==2' Source.txt` 'NR==2 && (idx=index($0,lookupStr)) { $0=substr($0,1,idx-1) replacementStr substr($0,idx+length(lookupStr)) } 1' Target.txt > temp.txt && mv temp.txt Target.txt

Выполнение команды после выполнения Target.txt имеет следующую строку:

OldString ==> NewString
This is Target File containing NewString now.
OldString is to be replaced.
NewString won't get impacted.

Здесь я определил две переменные lookupStr и replaceStr. обе присвоены строке №1 и строке №2 Source.txt соответственно. Затем в строке Sencond файла Target.txt я заменяю содержимое $ 0 первым символом до индекса lookupStr (т.е. "OldString") затем добавление replaceStr (т.е. «NewString») и затем конкатенация остальных символов. В конце вывод записывается в temp.txt, и он переименовывается в Target.txt

screenshot of confirmation

. Если вам нужно выполнить это упражнение по замене всего файла, просто удалите условие NR == 2 && из приведенной выше команды.

-2
27.01.2020, 20:35

Если вы хотите, чтобы замены производились независимо друг от друга, например, для:

foo -> bar
bar -> foo

Подано на

foobar

В результате:

barfoo

в отличие от foofooкак сделал бы наивный s/foo/bar/g; s/bar/foo/gперевод, вы могли бы сделать:

perl -pe '
  BEGIN{
    open STRINGS, "<", shift@ARGV or die"STRINGS: $!";
    open REPLACEMENTS, "<", shift@ARGV or die "REPLACEMENTS: $!";
    while (defined($a=<STRINGS>) and defined($b=<REPLACEMENTS>)) {
      chomp ($a, $b);
      push @repl, $b;
      push @re, "$a(?{\$repl=\$repl[". $i++. "]})"
    }
    eval q($re = qr{). join("|", @re). "}";
  }
  s/$re/$repl/g' strings.txt replacements.txt fileA 

В patterns.txtожидается perlрегулярных выражений. Поскольку регулярные выражения Perl могут выполнять произвольный код, важно, чтобы они были очищены. Если вы хотите заменить только фиксированные строки, вы можете изменить это на:

perl -pe '
  BEGIN{
    open PATTERNS, "<", shift@ARGV or die"PATTERNS: $!";
    open REPLACEMENTS, "<", shift@ARGV or die "REPLACEMENTS: $!";
    for ($i = 0; defined($a=<PATTERNS>) and defined($b=<REPLACEMENTS>); $i++) {
      chomp ($a, $b);
      push @string, $a;
      push @repl, $b;
      push @re, "\\Q\$string[$i]\\E(?{\$repl=\$repl[$i]})"
    }
    eval q($re = qr{). join("|", @re). "}";
  }
  s/$re/$repl/g' patterns.txt replacements.txt fileA 
2
27.01.2020, 20:35

Теги

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