Можно обернуть fold
, затем head
его:
onepage () {
fold -w "$(tput cols)" -s "$@" |
head -n "$(($(tput lines)-1))"
}
Или, может быть, используйте pr
. Предполагая, что GNUpr
:
pr -l "$((LINES - 1))" +1:1 -t
-l...
-установить высоту страницы на$LINES
-1. +1:1
начать печать с первой страницы... до первой страницы. -t
-не печатать заголовок. #! /bin/bash
# get.sh
IFS=$'\n'
args=(`sort -nu <<<$*`)
unset IFS
awk -v lines="${args[*]}" 'BEGIN{split(lines, ar, " ");}{ for (i in ar) { if (NR == ar[i]) print $1,$2} }' data.txt
Сначала создается массив args
, содержащий отсортированные и уникальные значения. Для этого мы использовали опции -n
и -u
. Посмотреть подробнее деталь .
Затем split
создает массив ar
из переменной lines
. Теперь для цикла вывести требуемый вывод, если элемент в ar
равен записи номер (NR ).
В awk вы могли собирать номера строк в массив и читать файл один раз, печатая строки, упомянутые в массиве:
#!/bin/sh
awk -v lines="$*" 'BEGIN { split(lines, a, "[, ]");
for (i in a) b[a[i]] = 1;}
NR in b {print $1, $2}' < data.txt
Цикл split()
разбивает переменную lines
по пробелам и запятым в массив a
, а цикл for
строит массив b
таким образом, что ключи этого массива содержат интересующие нас строки. Затем NR in b
просто проверяет, существует ли ключ, соответствующий текущему номеру строки.
Обратите внимание, что каждая строка будет напечатана только один раз, независимо от того, сколько раз она встречается во входных данных, и строки будут напечатаны в порядке ввода, а не в порядке, заданном аргументом:
$ bash get.sh 7 3 3
3 cFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
7 gFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
(get.sh 7,3,3
тоже работает)
Поместите приведенные ниже строки в текстовый файл и назовите его get.sh. затем сделайте его исполняемым.
#!/bin/sh
## this is GNU sed
sed -En "
$(printf '%sbp\n' "$@" "d;")
:p;s/\S+/&\n/2;P
" data.txt
Теперь вызовите скрипт, как показано:
chmod +x./get.sh
./get.sh 1 3 5
Следующий bash
скрипт создает скрипт sed
, который изменяет и отображает строки по номерам, указанным в командной строке:
#!/bin/bash
sed_script=()
for lineno do
sed_script+=( -e "$lineno ba" )
done
sed "${sed_script[@]}" \
-e 'd' -e ':a' -e 's/[[:blank:]]*[^[:blank:]]*$//' <data.txt
или, для/bin/sh
:
#!/bin/sh
for lineno do
set -- "$@" -e "$lineno ba"
shift
done
sed "$@" -e 'd' -e ':a' -e 's/[[:blank:]]*[^[:blank:]]*$//' <data.txt
При выполнении как ./get.sh 1 3 5
оба этих скрипта завершатся выполнением команды
sed -e '1 ba' -e '3 ba' -e '5 ba' -e d -e :a -e 's/[[:blank:]]*[^[:blank:]]*$//' <data.txt
Это соответствует скрипту sed
1 ba
3 ba
5 ba
d
:a
s/[[:blank:]]*[^[:blank:]]*$//
Подстановка s/[[:blank:]]*[^[:blank:]]*$//
удалит последний столбец в данных (последняя серия пробелов или табуляции следует за серией не -пробелов и не -табуляций в конце строки ). Остальная часть кода sed
гарантирует, что выполнение переходит к метке :a
, если мы находимся на одной из строк, которые мы хотим вывести (это то, что делает ba
), и что в противном случае текущая строка удаляется с помощью d
.
Вы можете изменить это и удалить жестко закодированное -перенаправление из data.txt
в скрипте. Вместо этого вы можете перенаправить любой поток данных, который хотите обработать :
$./get.sh 1 2 9 <data.txt
1 aFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
2 bFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
9 iFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
Аналогичный подход вawk
:Дайте коду awk
кучу пробелов -номера строк с разделителями из командной строки скрипта (приведенный ниже код получает их из lineno
переменной окружения, установленной вызов оболочки ). Распакуйте их в ключи в таблице поиска(lines
)в блоке BEGIN
, а затем просто проверьте, является лиFNR
(текущий номер строки в текущем файле )ключом в этой таблице поиска.
#!/bin/sh
lineno="$*" awk '
BEGIN {
n = split(ENVIRON["lineno"], a, " ")
for (i = 1; i <= n; ++i)
lines[a[i]] = 1
}
FNR in lines { print $1, $2 }'
(FNR in lines
можно заменить на lines[FNR]
, чтобы единицы, которые мы сохраняем как значения, действительно стали полезными.)
Тестирование:
$./get.sh 3 4 8 <data.txt
3 cFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
4 dFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
8 hFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
#!/bin/bash
perl -le '
for (@ARGV) {
# separate command line args into filename(s) and line-number(s)
# line-numbers can be space and/or comma separated.
if (-e $_) { push @files, $_ } else { push @lines, split /,/};
};
@ARGV = @files;
$re = join("|",@lines);
while(<>) {
print join("\t",(split)[0..1]) if ($. =~ m/^($re)$/);
close(ARGV) if eof;
}' "$@"
Это строит регулярное выражение из аргументов, отличных от -имени файла, которые позже используются для сопоставления с номерами строк -каждого файла. При совпадении он разделяет строку ввода пробелами и печатает первые два поля, разделенные табуляцией.
close(ARGV)
нужен только потому, что нас интересует номер строки текущего файла, а не номер строки -всех входных данных, просмотренных до сих пор. perl сбрасывает переменную $.
(, также известную как $NR
или $INPUT_LINE_NUMBER
), только когда дескриптор файла закрывается, но дескрипторы файлов обычно не закрываются в цикле while(<>)
.Это просто явно закрывает дескриптор файла, так что $.
сбрасывается. См. perldoc -f eof
.
$./get.sh 1 3,5 data.txt
1 aFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
3 cFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
5 eFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
Этот скрипт, конечно же, должен быть Perl-скриптом, а не бессмысленной bash-оболочкой Perl «одного -лайнера». Но люди, кажется, думают, что один лайнер -является "правильным", в то время как скрипты, использующие что-либо, кроме #!/bin/bash или #!/bin/sh в качестве интерпретатора, в чем-то неверны.
#!/usr/bin/perl -l
for (@ARGV) {
# separate command line args into filename(s) and line-number(s)
# line-numbers can be space and/or comma separated.
if (-e $_) { push @files, $_ } else { push @lines, split /,/ };
};
@ARGV = @files;
$re = join('|',@lines);
while(<>) {
print join("\t",(split)[0..1]) if ($. =~ m/^($re)$/);
close(ARGV) if eof;
};
$./get.pl 1 3,5 data.txt
1 aFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
3 cFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
5 eFDLKSFD_FDSJFskadfsff_fsadklfj_fdsaf
Это делает в точности то же самое, не тратя впустую ничтожное количество времени и памяти на разветвление интерпретатора оболочки, который ничего не делает, кроме разветвления интерпретатора perl.
Что еще более важно, это позволяет избежать проблем с цитированием оболочки , поскольку оболочка не задействована. Кроме того, подсветка синтаксиса корректно работает в вашем редакторе, потому что сценарий — это не просто строка в кавычках внутри сценария оболочки. И номера строк -верны в предупреждениях/сообщениях об ошибках при отладке скрипта, потому что они относятся к абсолютному номеру строки -файла скрипта, а не к относительному номеру строки внутри одного -вкладыш.