2012-06-08 3 views
15

Скажет у вас есть простой циклBash loop, распечатать текущую итерацию?

while read line 
do 
    printf "${line#*//}\n" 
done < text.txt 

Есть элегантный способ печати текущей итерации с выходом? Что-то вроде

 
0 The 
1 quick 
2 brown 
3 fox 

Я надеюсь избежать установки переменной и увеличения ее на каждый цикл.

ответ

21

Чтобы сделать это, вам нужно будет увеличивать счетчик на каждой итерации (как вы пытаетесь избежать).

count=0 
while read -r line; do 
    printf '%d %s\n' "$count" "${line*//}" 
    ((count++)) 
done < test.txt 

EDIT: После того, как еще некоторые мысли, вы можете сделать это без рецепта, если у вас есть Баш версии 4 или выше:

mapfile -t arr < test.txt 
for i in "${!arr[@]}"; do 
    printf '%d %s' "$i" "${arr[i]}" 
done 

файле проекта встроенной считывает все содержимое файла в массив , Затем вы можете перебирать индексы массива, которые будут номерами строк и доступ к этому элементу.

+2

Хорошее решение, хотя 'mapfile' может быть ужасно голодной памятью, если вы имеете дело с большими файлами.Не зная размер файла OP, я бы порекомендовал идти с чем-то, что проходит через трубу, и поэтому агрегирует размер файла. – ghoti

0

Обновление: Другие ответы, размещенные здесь, лучше, особенно те из @Graham и @DennisWilliamson.

Что-то очень, как это должно удовлетворить:

tr -s ' ' '\n' <test.txt | nl -ba 

Вы можете добавить -v0 флаг команды nl если вы хотите индексировать от 0.

+0

Ярмарка достаточно. Тогда будет ли командование «nl» само по себе? – thb

+0

У меня нет команды 'n1' в FreeBSD, OSX или Illumos. Откуда это? – Graham

+1

Ах - досадные моноширинные шрифты. @thb, я думаю, вам все равно нужно что-то стричь строки до '//', как '$ {line # * //}'. Но вы, безусловно, могли бы пропустить цикл while через «nl», как и в «grep -n.» В моем ответе. – Graham

1
n=0 
cat test.txt | while read line; do 
    printf "%7s %s\n" "$n" "${line#*//}" 
    n=$((n+1)) 
done 

Это, конечно, будет работать и в корпусе Бурна.

Если вы действительно хотите, чтобы избежать инкремент переменной, вы можете трубы выход через Grep или AWK:

cat test.txt | while read line; do 
    printf " %s\n" "${line#*//}" 
done | grep -n . 

или

awk '{sub(/.*\/\//, ""); print NR,$0}' test.txt 
+0

Отредактировано для включения опции для ваших окончательных критериев. – Graham

+0

Я предпочитаю решение awk, хотя 'sub (/.*\/\//," ");' is * not * то же самое, что '$ {line # * //}' – ghoti

+1

Ну ... первая часть вашего ответа в значительной степени идентичны jordanm's, и два дополнительных, похоже, работают очень хорошо. Извлеките его до случайности StackOverflow. :-) – ghoti

13

Вы не часто видите, но вы можете имеют несколько команд в условии условия цикла while. Следующее по-прежнему требует явной переменной счетчика, но расположение может быть более подходящим или привлекательным для некоторых целей.

while ((i++)); read -r line 
do 
    echo "$i $line" 
done < inputfile 

Условие while удовлетворяет каким-либо последняя команда возвращает (read в данном случае).

Некоторые люди предпочитают включать do в той же строке. Вот как это выглядит:

while ((i++)); read -r line; do 
    echo "$i $line" 
done < inputfile 
+2

+1 Я не знал, пока синтаксис допустил это. – jordanm

+4

@jordanm: 'for' делает что-то подобное:' for ((i = 0, j = 14; i <= 20; i ++, j + = 11)) '. Кроме того, вы можете читать две (или более) строки из файла за раз: 'while read -r oddline; читать -r равномерное; do echo "odd: [$ oddline] even: [$ evenline]"; done

Смежные вопросы