Bash цикл, текущая итерация печати?
Скажем, у вас простой цикл
while read line
do
printf "${line#*//}\n"
done < text.txt
Есть ли элегантный способ печати текущей итерации с выходом? Что-то вроде
0 The
1 quick
2 brown
3 fox
Я надеюсь избежать установки переменной и увеличения ее в каждом цикле.
Ответы
Ответ 1
Для этого вам нужно увеличить счетчик на каждой итерации (например, вы пытаетесь избежать).
count=0
while read -r line; do
printf '%d %s\n' "$count" "${line*//}"
(( count++ ))
done < test.txt
РЕДАКТИРОВАТЬ: после некоторых размышлений вы можете сделать это без счетчика, если у вас bash версия 4 или выше:
mapfile -t arr < test.txt
for i in "${!arr[@]}"; do
printf '%d %s' "$i" "${arr[i]}"
done
Встроенный файл mapfile считывает все содержимое файла в массив. Затем вы можете перебирать индексы массива, которые будут номерами строк и доступ к этому элементу.
Ответ 2
Вы не часто видите это, но вы можете иметь несколько команд в условии условия цикла 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
Ответ 3
n=0
cat test.txt | while read line; do
printf "%7s %s\n" "$n" "${line#*//}"
n=$((n+1))
done
Это тоже будет работать в оболочке Bourne.
Если вы действительно хотите избежать приращения переменной, вы можете вывести ее через grep или awk:
cat test.txt | while read line; do
printf " %s\n" "${line#*//}"
done | grep -n .
или
awk '{sub(/.*\/\//, ""); print NR,$0}' test.txt
Ответ 4
Обновление: другие ответы, размещенные здесь, лучше, особенно те, что были @Graham и @DennisWilliamson.
Что-то очень похоже на это:
tr -s ' ' '\n' <test.txt | nl -ba
Вы можете добавить флаг -v0
в команду nl
, если хотите индексировать с 0.