Розбір обмеженого текстового файлу в bash як аргументи команди


10

У мене текстовий файл розділений так:

field1,field2,field3 
xield1,xield2,xield3 
dield1,dield2,dield3 
gield1,gield2,gield3

Кожен із цих стовпців буде параметром програми, і я хотів би, щоб програма викликалася для кожного рядка

Я сподівався на цикл, щось на кшталт:

for $i in file
    command $field2 -x $field3 -PN -$field1 >> output
done

Що було б найкращим способом здійснити щось подібне в баш?


Чи кількість полів є постійною?
— Джозеф Р.

@JosephR. так, вони є, завжди 3
— Декан

Відповіді:


7
while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

Це повинно працювати, якщо кількість полів є постійною. Замість echoвикористання вашої команди.


Дякую, я просто намагався це зробити, але, здається, це працює лише для першого рядка. Як тільки команда вдається, вона не спробує наступну, якщо вона не вдасться, вона спробує наступну, хоча ...
— Декан

Як ви маєте на увазі успіх чи невдачу? Що робить ваша команда?
— coffeMug

Я б здогадався, що команда, яку він виконує, - це зчитування стандартного вводу, перш ніж команда "прочитати" зможе отримати це.
— plugwash

4

Ви повинні використовувати whileз readвбудованими:

while IFS= read -r line;do
    fields=($(printf "%s" "$line"|cut -d',' --output-delimiter=' ' -f1-))
    command "${fields[1]}" -x "${fields[2]}" ... # ${fields[1]} is field 2
done < your_file_here

Як це працює

  • Оператор cutбере рядок і розбиває його на роздільник, заданий -d.
  • Це --output-delimiterсимвол роздільника, який cutбуде використовуватися для відображення вибраних полів, тут ми вибираємо пробіл, щоб ми могли помістити різні поля в масив fields.
  • Нарешті, ми хочемо, щоб усі поля (від поля 1 до кінця) і ось десь -f1-вступали в гру.
  • Тепер у вас є різні поля , що зберігаються в змінної масиву fields, ви можете отримати доступ до будь-якої конкретної області ви хочете з синтаксисом , ${field[number]}де numberодин менше , ніж фактична кількість поля ви хочете , так як індексація масиву починається з нуля в Bash.

Примітка

  • Це не вдасться, якщо будь-яке ваше поле містить пробіл.

Для постійної кількості полів

Ви можете замість цього зробити щось подібне до відповіді 1_CR :

while IFS= read -r line;do
    IFS=, read -r field1 field2 field3 <<-EOI
    $line
    EOI
    command "$field2" -x "$field3" ... 
done < your_file_here

Вищезазначене, хоч і здається більш галасливим, має працювати в будь-якій оболонці, сумісній з POSIX, а не тільки в Bash.


З моїми проблемами це не читання файлу, це розбиття рядка на стовпці.
— Декан

@Dean Так, вибачте Я не звертав уваги. Працюємо над цим зараз.
— Джозеф Р.

@Dean Перегляньте оновлену відповідь. Я скоро додам пояснення.
— Джозеф Р.

@JosephR., Можливо уникнути використання зовнішніх інструментів для розбиття, встановивши IFSвідповідне значення у readвиклику
— iruvar

@ 1_CR Я знаю, дякую. Я щойно до цього добирався :)
— Джозеф Р.

1

Ви можете readділити кожен рядок на масив ,, встановивши IFSвідповідним чином.

while IFS=, read -r -a input; do
 printf "%s\n" "${input[0]}" "${input[1]}"
done < input.txt

Так у наведеному вище прикладі ви можете отримати доступ до кожного елемента масиву, використовуючи його індекс, починаючи з 0.


1

Цей awkоднопластовий виконає все, що ви хочете:

awk -F, '{cmd="echo " $2 " -x " $3 " -PN " $1 ">> output";  system(cmd)}' f.txt

Замініть echoсвою команду та f.txtфайл, який ви хочете повторити.

Коротке пояснення: -F,буде встановлено ,як роздільник. cmdбудує команду і system(cmd)викликає команду.


1

gnu sed також можна використовувати.

sed infile -e 's!^\([^,]*\),\([^,]*\),\([^,]*\)$!command \1 -x \2 -PN \3!e' >> output

зауважте використання параметра e для команди s

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.