У меня есть такая простая команда
grep 'X' results.dat | awk '{print $NF}' > Y.dat
Я хочу зациклить эту команду, взяв Xs из столбца 1 и соответствующие Ys из столбца 2 того же файла например. Файл NAMES
NAMES имеет формат
C11-C12 p01
C13-C14-C17 P02
etc ..
, поэтому первые два шага цикла должны быть такими:
grep 'C11-C12' results.dat | awk '{print $NF}' > p01.dat
grep 'C13-C14-C17' results.dat | awk '{print $NF}' > p02.dat
Решение, которое не требует цикла в оболочке:
awk 'pass==1 { Xpatt[NR] = $1; Yfile[NR] = $2 ".dat"; printf "" > Yfile[NR] }
pass==2 {
for (i in Xpatt) {
if ($0 ~ Xpatt[i]) print $NF > Yfile[i]
}
}' pass=1 NAMES pass=2 results.dat
Прежде всего,
awk
позволяет вам указывать назначения переменных в качестве аргументов командной строки, {{1} } после программы, смешанные с именами файлов, без использования -v
.
Они выполняются в той точке последовательности обработки
, которую предлагает их позиция в командной строке.
Итак, в приведенной выше команде
pass
получает установлено значение 1, NAMES
, pass
получает значение 2, а затем results.dat
. Думаю, я мог бы установить pass = 1
с помощью -v
или в блоке BEGIN
.
Я использую переменную pass
, чтобы указать, какой файл я читаю.
Обычно это делается путем сравнения NR
с FNR
,
, но это может привести к ложным показаниям, если файл пуст.
(Строго говоря, я полагаю, что этот сценарий должен проверять, является ли какой-либо из файлов пустым, потому что в этом случае работать не нужно.)
pass == 1
(мы читаем файл NAMES
),
сохраняем значения X и Y (шаблон и имя файла)
из столбцов 1 и 2 ( $ 1
и $ 2
) этого файла.
Создайте выходной файл ( Yfile [NR]
), потому что,
если мы этого не сделаем здесь, мы не получим (пустые) выходные файлы {{1} } для шаблонов, которых нет в файле results.dat
.
(Если вас это устраивает, опустите инструкцию printf
.) pass == 2
(мы читаем файл results.dat
),
перебирает шаблоны в NAMES
] файл
и выведите последнее слово из каждой строки, которая соответствует шаблону
, в соответствующий файл - то есть, эквивалент
OP grep X… | awk '{print $ NF}'> команда Y.dat
. Решение на Bash:
while read X Y remainder || [[ -n ${Y} ]]; do
awk -v X="$X" '$0 ~ $X {print $NF}' results.dat > "$Y".dat
done < NAMES
Обычно , когда IFS = "q", читается остаток XY; делать ...; done
NAMES
. Он разделит значения в каждой строке на основе значения IFS
(внутренний разделитель полей). В этом примере IFS
установлен на букву q
. IFS
по умолчанию использует пробелы (пробелы, табуляции или новые строки). Первому полю присваивается переменная X
, второму - Y
, а остальной части строки - остатку
.
См. Также: Чтение столбцов из файла в отдельные переменные (Unix.SE).
В приведенном выше решении IFS
не указан, потому что я предполагаю , что ваши поля уже разделены пробелами.
Примечание: если поля в вашем файле NAMES
содержат обратную косую черту, вам необходимо использовать read -r
, чтобы предотвратить чтение
от интерпретации обратной косой черты как escape-последовательности. .
...остаток || [[-n $ {остаток}]]
часть обрабатывает две вещи: любые дополнительные поля, если таковые имеются, сохраняются в остатке
; и обрабатывает случай, если последняя строка вашего входного файла не заканчивается новой строкой \ n
( read
возвращает ненулевой код выхода при обнаружении EOF).
См. Также: Прочитать файл построчно, присвоив значение переменной (SO).
Полностью удалить grep
: awk -v X = "$ X" '$ 0 ~ $ X {print $ NF}' results.dat> "$ Y" .dat
. Параметр -v
для awk
определяет переменную, которая может использоваться в сценарии awk
.