it-swarm-ru.tech

Как зациклить строки файла?

Скажи, у меня есть этот файл:

_hello
world
hello world
_

Эта программа

_#!/bin/bash

for i in $(cat $1); do
    echo "tester: $i"
done
_

Результаты

_tester: hello
tester: world
tester: hello
tester: world
_

Я хотел бы, чтобы for итерировался по каждой строке индивидуально, игнорируя пробелы, то есть последние две строки должны быть заменены на

_tester: hello world
_

Использование кавычек for i in "$(cat $1)"; приводит к тому, что i назначается весь файл сразу. Что я должен изменить?

63
Tobias Kienzler

С for и ​​ IFS :

#!/bin/bash

IFS=$'\n'       # make newlines the only separator
set -f          # disable globbing
for i in $(cat < "$1"); do
  echo "tester: $i"
done

Однако обратите внимание, что он пропускает пустые строки как символ новой строки , являющийся символом пробела IFS, его последовательности считаются равными 1, а начальная и конечная - игнорируются. С zsh и ​​ksh93 (не bash), вы можете изменить его на IFS=$'\n\n', чтобы символ новой строки не обрабатывался специально, однако учтите, что все завершающие символы новой строки (включая завершающие пустые строки) всегда будут удаляться командой замена.

Или с read (не более cat):

#!/bin/bash

while IFS= read -r line; do
  echo "tester: $line"
done < "$1"

Там сохраняются пустые строки, но имейте в виду, что последняя строка будет пропущена, если она не будет правильно разделена символом новой строки.

76
wag

Для чего это стоит, мне нужно делать это довольно часто, и я никогда не могу вспомнить точный способ использования while IFS= read..., поэтому я определил следующую функцию в своем профиле bash:

# iterate the line of a file and call input function
iterlines() {
    (( $# < 2 )) && { echo "Usage: iterlines <File> <Callback>"; return; }
    local File=$1
    local Func=$2
    n=$(cat "$File" | wc -l)
    for (( i=1; i<=n; i++ )); do
        "$Func" "$(sed "${i}q;d" "$File")"
    done
}

Эта функция сначала определяет количество строк в файле, затем использует sed для извлечения строки за строкой и передает каждую строку в качестве единственного строкового аргумента любой данной функции. Я предполагаю, что это может стать действительно неэффективным с большими файлами, но это не было проблемой для меня до сих пор (предложения по улучшению этого приветствия, конечно).

Использование довольно сладкое ИМО:

>> cat example.txt # note the use of spaces, whitespace, etc.
a/path

This is a sentence.
"wi\th quotes"
$End
>> iterlines example.txt echo # preserves quotes, $ and whitespace
a/path

This is a sentence.
"wi\th quotes"
$End
>> x() { echo "$#"; }; iterlines example.txt x # line always passed as single input string
1
1 
1
1
1
1
Jonathan H