Я новичок в написании сценариев и у меня есть требование, как показано ниже.

Существует файл с именем jobname.txt с приведенным ниже содержимым.

job1
job2

Существует файл с именем value.txt с приведенным ниже содержимым.

10
20

Мне нужно распечатать вывод, например

update_job: job1
max_run_alarm: 10

update_job: job2
max_run_alarm: 20

Как я могу сделать это с помощью сценария оболочки или awk?

1
αғsнιη 12 Май 2021 в 15:01

8 ответов

Лучший ответ

С awk:

awk '{printf "update_job: %s\n", $1 ; getline < "value.txt"; printf "max_run_alarm: %s\n\n", $1 }' jobname.txt

Первая команда printf печатает строку из первого файла jobname.txt. Затем команда getline берет строку из файла value.txt. Затем команда printf печатает эту строку.

См. http://awk.freeshell.org/AllAboutGetline, чтобы узнать, когда и как использовать getline.

2
Prabhjot Singh 12 Май 2021 в 15:37

С paste+awk:

$ paste -d'\n' jobname.txt value.txt \
  |awk '{ print (NR%2?"update_job:":"max_run_alarm:", $0) }'

По сути, с помощью команды paste, как следует из ее названия, мы вставляем оба файла построчно из каждого, но добавляем один символ \n ewline между каждой строкой, затем мы повторно обрабатываем предыдущий вывод с помощью awk и мы добавляем нужный "текст" для строк, номер строки которых равен модулю 2 (строки с четными номерами строк, например, номера строк 2, 4, 6, ...; NR содержит номер строки, которую awk считывает для обработки) мы добавляем текст "update_job:" или для нечетных номеров строк мы добавляем текст " max_run_alarm:", затем напечатайте саму строку $0.

Всего лишь awk:

awk 'NR==FNR{ 
    getline val<ARGV[2]; print "update_job:", $0 ORS "max_run_alarm:", val; next
}
{ exit }' jobname.txt value.txt

Здесь мы обрабатываем по-другому, выше мы сказали, что NR — это номер строки, здесь вы видите FNR; NR и FNR всегда имеют одно и то же значение (т. е. они оба содержат номер строки), но NR продолжает увеличиваться для всех строк всех входных файлов, а FNR сбрасывается обратно на 1, как только будет прочитан следующий входной файл (если есть) , поэтому, говоря NR==FNR, мы гарантируем, что следующий блок кода будет выполняться только для первого входного файла.

Затем мы вызываем "getline в переменную из файла< /a>", чтобы прочитать одну строку из второго аргумента, который мы передали в качестве входных данных (здесь ARGV[2] вернуть value.txt) и сохранить в переменную val; то остальное просто печатает вещи. ORS печатает разрыв строки между каждым.

Или, может быть, вы предпочитаете этот (но мне не нравится жесткое кодирование имени файла):

awk '{ 
    getline val<"value.txt"; print "update_job:", $0 ORS "max_run_alarm:", val
}' jobname.txt
7
αғsнιη 12 Май 2021 в 16:08
$ paste jobname.txt value.txt |
    awk '{printf "update_job: %s\nmax_run_alarm: %s\n\n", $1, $2}'
update_job: job1
max_run_alarm: 10

update_job: job2
max_run_alarm: 20

Или все в awk:

$ awk '
    NR==FNR { jobs[NR]=$1; next }
    { printf "update_job: %s\nmax_run_alarm: %s\n\n", jobs[FNR], $1 }
' jobname.txt value.txt
update_job: job1
max_run_alarm: 10

update_job: job2
max_run_alarm: 20

Оба вышеперечисленных используют обязательные инструменты POSIX и поэтому будут работать в любой оболочке на каждой машине Unix.

3
Ed Morton 12 Май 2021 в 19:52

В bash самый простой способ сделать это — прочитать оба файла в два разных массива, а затем выполнить итерацию от 1 до длины одного из массивов.

Bash имеет встроенную команду mapfile для быстрого чтения файлов в массивы, поэтому я воспользуюсь ею.

Например, используя массивы j и v для заданий и значений:

$ cat mapping.sh 
#!/bin/bash

mapfile -t -O 1 j < jobname.txt
mapfile -t -O 1 v < values.txt

for i in $(seq 1 "${#j[@]}") ; do
  printf "update_job: %s\n" "${j[$i]}"
  printf "max_run_alarm: %s\n\n" "${v[$i]}"
done

Пример вывода:

$ chmod +x ./mapping.sh
$ ./mapping.sh 
update_job: job1
max_run_alarm: 10

update_job: job2
max_run_alarm: 20

В awk:

$ cat mapping.awk
#!/usr/bin/awk -f

FNR==NR { # reading first file
  j[i++] = $0
  next;
}

{ # reading second file
  v[n++] = $0
}

END {
  for (i in j) {
      printf "update_job: %s\n", j[i]
      printf "max_run_alarm: %s\n\n", v[i]
  }
}

Выход:

$ chmod +x ./mapping.awk
$ ./mapping.awk jobname.txt values.txt 
update_job: job1
max_run_alarm: 10

update_job: job2
max_run_alarm: 20
2
cas 12 Май 2021 в 15:37
 co=`awk 'END{print NR}'  jobname.txt`

for ((i=1;i<=$co;i++)); do awk -v i="$i" 'NR==i{print "update_job: "$1}' jobname.txt; awk -v i="$i" 'NR==i{print "max_run_alarm: "$1}' value.txt;echo -e "\n"; done

Выход

update_job: job1
max_run_alarm: 10


update_job: job2
max_run_alarm: 20
2
Praveen Kumar BS 12 Май 2021 в 22:02

В bash... с использованием дополнительного файлового дескриптора оба файла могут одновременно выполняться в цикле while следующим образом:

while read -r j
do
    read -r v <&4
    printf "update_job: %s\nmax_run_alarm: %s\n\n" "$j" "$v"
done <"jobname.txt" 4<"value.txt"

Давая этот конечный результат:

update_job: job1
max_run_alarm: 10

update_job: job2
max_run_alarm: 20

1
Raffa 13 Май 2021 в 04:35

Используя GNU sed, мы можем сделать это, запустив два sed параллельно и вставив вывод одного в пространство шаблонов другого с помощью команды R

$ < values.txt \
  sed -e 's/^/max_run_alarm: /' \
| sed -e '
    s/^/\nupdate_job: /
    1s/.//; R/dev/stdin
' keys.txt

Еще один способ — использовать python3 и заархивировать итераторы двух дескрипторов файлов:

$ python3 -c 'import sys
keys,values = sys.argv[1:]
p,q = "update_job:","max_run_alarm:"
with open(keys) as k, open(values) as v:
  for a,b in zip(k,v):
    print(p,a+q,b,sep=" ")
' keys.txt values.txt

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

$ perl -ne '
  print for(
    "update_job: $_",
    "max_run_alarm: ".<STDIN>."\n");
' keys.txt < values.txt

Вывод:

update_job: job1
max_run_alarm: 10

update_job: job2
max_run_alarm: 20
0
guest_7 14 Май 2021 в 05:28

Если ed доступен / приемлем.

Скрипт script.ed

$t.
s/.\{1,\}//
1r value.txt
$m$-3
$-1m$
g/./s/^\(job[0-9]\{1,\}\)$/update_job: \1/\
s/^\([0-9]\{1,\}\)$/max_run_alarm: \1/
,p
Q

Тогда беги

ed -s jobname.txt < script.ed

  • Измените Q на w, если вас устраивает вывод и редактирование на месте.

  • Удалите ,p, чтобы заглушить вывод.

0
Jetchisel 5 Июл 2021 в 12:36