У меня есть управляющий файл - cntl.txt
2
3
5
Файл данных - data.txt
red
blue
yellow
green
violet
orange
Мне нужно прочитать соответствующие строки из управляющего файла, здесь ожидаемый вывод:
blue
yellow
violet
решение1
Пример очень неэффективного решения:
for i in $(<control.txt); do awk -v c=$i 'NR~c{ print $0 }' data.txt; done;
Я также сообщаю о хорошем решении, которое я узнал сегодня вечером:
awk 'FNR==NR{ z[$0]++;next }; FNR in z' control.txt data.txt
решение2
Используя толькоУказано POSIXособенности Sed:
sed -n -e "$(sed '/./s/$/p/' cntl.txt)" data.txt
Конечно, если в вашем cntl.txt
файле есть строки помимо цифр, вы можете получить ошибку. Но если в нем есть пустые строки, они будут обработаны правильно (т.е. они не повлияют на вывод).
решение3
Попробуй это:
join <(nl data.txt|sort -k1b,1) <(cat cntl.txt|sort -k1b,1) | sort -nk1,1 | cut -d' ' -f2-
nl - перечислит вам строки
1 red
2 blue
3 yellow
4 green
5 violet
6 orange
| sort -k1b,1 - отсортирует их по номеру строки (первое поле), лексикографически
cat cntl.txt| sort -k1b,1 - отсортирует контрольный файл в том же порядке
2
3
5
join <() <() - объединит отсортированные (и пронумерованные) «данные» с отсортированным «элементом управления» по первому полю (т.е. номеру строки)
2 blue
3 yellow
5 violet
|sort -nk1,1 — пересортирует результаты по числам (чтобы привести строки в порядок)
| cut -d' ' -f2- - удалит поле номера строки
blue
yellow
violet
решение4
Другое возможное решение:
IFS=$'\n' read -d '' -r -a colors < 'data.txt'; unset IFS;
for i in $(<cntl.txt); do
echo ${colors[i-1]}
done
Строка IFS устанавливает внутренний разделитель файлов как новую строку и вставляет каждую строку из data.txt в массив. После этого вы проходите по строкам в cntl.txt и печатаете элементы массива с указанным индексом из него (минус 1, потому что вы начинаете свой data.txt с 1, а не с 0, иначе это было бы ненужно).