Допустим, у меня есть стандартный терминал из 80 столбцов, я выполняю команду с выводом на длинные строки (т.е. stdout из ls), который разбивается на две или более строки, и хочу сделать отступ для строки продолжения всего моего stash-выхода bash.

Отступ должен быть настраиваемым, 1 или 2 или 3 или любые другие пробелы.

Из этого

lrwxrwxrwx 1 root root 24 Feb 19 1970 sdcard -> /storage/emula
ted/legacy/

К этому

lrwxrwxrwx 1 root root 24 Feb 19 1970 sdcard -> /storage/emula
ted/legacy/

Прочитайте этот отступ в несколько строк в сценарии оболочки, чтобы Я попытался передать по конвейеру | sed 's/^/ /', но дает прямо противоположное: отступает первые строки, а не продолжение.

В идеале я бы помещал скрипт в profile.rc или что-то в этом роде, поэтому каждый раз, когда я открываю интерактивную оболочку и выполняю любую команду, длинный вывод получает отступ.

2
Ju Tutt 3 Май 2019 в 11:56

3 ответа

Лучший ответ

Для этого я бы использовал .

awk -v width="$COLUMNS" -v spaces=4 '
BEGIN {
  pad = sprintf("%*s", spaces, "") # generate `spaces` spaces
}
NF {                               # if current line is not empty
  while (length > width) {         # while length of current line is greater than `width`
    print substr($0, 1, width)     # print `width` chars from the beginning of it
    $0 = pad substr($0, width + 1) # and leave `pad` + remaining chars
  }
  if ($0 != "")                    # if there are remaining chars
    print                          # print them too 
  next
} 1' file

В одну строку:

awk -v w="$COLUMNS" -v s=4 'BEGIN{p=sprintf("%*s",s,"")} NF{while(length>w){print substr($0,1,w);$0=p substr($0,w+1)} if($0!="") print;next} 1'

Как @Mark предлагает в комментариях, вы можете поместить это в функцию и добавить ее в .bashrc для простоты использования.

function wrap() {
  awk -v w="$COLUMNS" -v s=4 'BEGIN{p=sprintf("%*s",s,"")} NF{while(length>w){print substr($0,1,w);$0=p substr($0,w+1)} if($0!="") print;next} 1'
}

Использование:

ls -l | wrap

Редактировать Эд Мортон за запрос:

Очень похоже на скрипт oguzismails выше, но должно работать с Busybox или любым другим awk:

$ cat tst.awk
BEGIN { pad = sprintf("%" spaces "s","") }
{
    while ( length($0) > width ) {
        printf "%s", substr($0,1,width)
        $0 = substr($0,width+1)
        if ( $0 != "" ) {
            print ""
            $0 = pad $0
        }
    }
    print
}
$
$ echo '123456789012345678901234567890' | awk -v spaces=3 -v width=30 -f tst.awk
123456789012345678901234567890
$ echo '123456789012345678901234567890' | awk -v spaces=3 -v width=15 -f tst.awk
123456789012345
   678901234567
   890
$ echo '' | awk -v spaces=3 -v width=15 -f tst.awk

$

Этот первый тестовый пример должен показать, что вы не печатаете пустую строку после полной строки ввода, а третий - показать, что он не удаляет пустые строки. Обычно я бы использовал sprintf("%*s",spaces,"") для создания строки pad, но я вижу в комментарии, что это не работает в явно не POSIX awk, который вы используете.

2
oguz ismail 4 Май 2019 в 09:08

Это может работать для вас (GNU sed):

sed 's/./&\n  /80;P;D' file

Это разбивает строки на длину 80 и выравнивает следующую строку (и) на 2 пробела.

Или, если вы предпочитаете:

s='  ' c=80
sed "s/./&\n$s/$c;P;D" file

Чтобы предотвратить печать пустых строк, используйте:

sed 's/./&\n/80;s/\n$//;s/\n    /;P;D' file

Или проще:

sed 's/./\n    &/81;P;D' file
1
potong 5 Май 2019 в 23:15

Одно возможное решение, использующее чистую манипуляцию строк bash. Вы можете заставить скрипт читать stdin и форматировать все, что он читает.

MAX_LEN=5  # length of the first/longest line
IND_LEN=2  # number of indentation spaces
short_len="$((MAX_LEN-IND_LEN))"
while read line; do
    printf "${line:0:$MAX_LEN}\n"
    for i in $(seq $MAX_LEN $short_len ${#line}); do
        printf "%*s${line:$i:$short_len}\n" $IND_LEN
    done
done

Использование: (при условии, что скрипт сохранен как indent.sh)

$ echo '0123456789' | ./indent.sh
01234
  567
  89
0
Sumudu 3 Май 2019 в 09:48