Розбір обмеженого текстового файлу в 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.