Решение, которое не требует цикла в оболочке:
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
. $ printf "%s\n" * | sed 's/.csv$//; s/_/\t/g'
abc q1 w1
defg q11 w2
hijk q11 w3
Как это работает:
printf "%s\n" *
печатает имена файлов по одному в строке
s/.csv$//
удаляет концевой .csv
.
s/_/\t/g
преобразует _
в табуляцию.
$ for f in *; do f="${f%.csv}"; printf "%s\n" "${f//_/$'\t'}"; done
abc q1 w1
defg q11 w2
hijk q11 w3
Если это поможет прояснить ситуацию, вышеприведенный код можно разбить на несколько строк:
for f in *
do
f="${f%.csv}"
printf "%s\n" "${f//_/$'\t'}"
done
${f%.csv}
удаляет идущие следом .csv
и ${f//_/$'\t'}
преобразует все _
в табуляции.
Мы не используем echo
для этой задачи, потому что, если одно из имен файлов начинается с -
, многие оболочки попытаются интерпретировать это имя файла как опцию, и результат будет не очень хорошим.
$ for f in "$dir"/*; do f="${f#$dir/}"; f="${f%.csv}"; printf "%s\n" "${f//_/$'\t'}"; done
abc q1 w1
defg q11 w2
hijk q11 w3