Як читати різні рядки файлу до різних змінних?


14

Я хотів би прочитати різні рядки текстового файлу до різних змінних. Наприклад

input.txt:

line1 foo foobar bar
line2 bar
line3 foo
line4 foobar bar

Я хочу , щоб цей результат буде зберігатися в змінних var1, var2, var3і var4такі , що

var1=line1 foo foobar bar
var2=line2 bar

і так далі.

Невже хтось скаже, як це робиться? Я намагався використовувати evalв циклі for. Це, здається, не працює.



3
Це поганий підхід. Оскільки в основному єдина причина набору змінних , щоб зробити що - то з ними, і так як існує величезна кількість інструментів , спеціально розроблених , щоб робити речі з кожним рядком тексту в файлі (Awk, Sed, grep, cut, і ін. І ін.), набагато краще просто робити те, що вам потрібно зробити. Не керуйте мікроконтролем у сценарії оболонки; оркеструвати інструменти, щоб виконати роботу.
Wildcard

Відповіді:


20

Ви зробите:

unset -v line1 line2
{ IFS= read -r line1 && IFS= read -r line2; } < input.txt

Або:

{ line1=$(line) && line2=$(line); } < input.txt

(менш ефективний, як lineрідко вбудований, і більшість оболонок потребують роздвоєння для здійснення заміни команд. lineтакож більше не є стандартною командою).

Для використання циклу:

unset -v line1 line2 line3
for var in line1 line2 line3; do
  IFS= read -r "$var" || break
done < input.txt

Або автоматично визначити імена змінних як line<++n>:

n=1; while IFS= read -r "line$n"; do
  n=$((n + 1))
done < input.txt

Зверніть увагу, що bashпідтримує змінні масиву та readarrayвбудований для читання рядків у масив:

readarray -t line < input.txt

Однак зауважте, що на відміну від більшості інших оболонок, bashіндекси масиву починаються з 0, а не 1 (успадковано від ksh), тому перший рядок буде входити ${line[0]}, а не ${line[1]}(хоча, як показало @Costas , ви можете змусити readarray(aka mapfile) почати записувати значення в індекси 1 ( bashмасиви також суперечать більшості інших оболонок, які є рідкісними масивами) з -O 1).

Дивіться також: Розуміння "IFS = read -r рядок"?


12

Я б запропонував використовувати масив для таких завдань

mapfile -t -O 1 var <input.txt

так що ви будете мати кожен рядок ${var[1]}, ${var[2]}і так далі


Цей однопластовий працює дуже добре. Вирішили питання для мене.
Метт

0

Про це ви не дуже відповідали, але це може спрацювати для ваших потреб. Ви можете серіалізувати дані за допомогою Awk. Зауважте, що це порушиться, якщо ваш $ 1 не є дійсним ім'ям змінної:

awk '
function quote(str,   d, m, x, y, z) {
  d = "\47"; m = split(str, x, d)
  for (y in x) z = z d x[y] (y < m ? d "\\" d : d)
  return z
}
{
  print $1 "=" quote($0)
}
' input.txt > /tmp/input.sh
. /tmp/input.sh

Результат:

$ echo "$line1"
line1 foo foobar bar

Це серйозно дивний код! Здається, ви використовуєте awk, щоб перетворити весь вхідний файл у скрипт bash, який ви потім джерелом. Я маю неясне уявлення про те, що цитата () робить. Більш описові назви змінних допоможуть. Чи можете ви пояснити речі трохи більше?
Джо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.