25,000개의 문자가 있습니다.
printf
나는 임의의 수의 문자를 순서대로 인쇄하는 스크립트를 작성하고 싶습니다 .
설명하다:
주문 번호
어디숫자1-25000 사이의 값이 될 수 있으며 이 출력을 얻을 수 있습니다.
나는 데이터를 별도의 파일에 저장하고 싶지 않으며(가장 쉬운 솔루션?) POSIX 쉘 명령을 사용하는 것을 선호합니다(스크립트를 가능한 한 이식 가능하게 만들기 위해: awk 또는 Perl이 이것을 간단하게 해킹할 수 있다는 것을 알고 있습니다). .
이 데이터를 변수에 저장해야 합니까? 아니면 명령( )을 printf
통해 전체 프로그램을 실행하시겠습니까 ? 아니면 또 다른 (더 나은?) 해결책이 있나요? 왜 다른 옵션보다 하나의 옵션을 선택해야 합니까?cut
cut -c -$1
내가 간과한 다른 문제/경고는 무엇입니까?
답변1
이 dd
순서를 생각해 보셨나요? 이를 통해 원하는 만큼의 바이트를 건너뛴 다음 원하는 만큼의 바이트를 출력할 수 있습니다.
dd if=infilename bs=1 skip=sk count=ct 2>/dev/null
dd
, 파일 이름 입력, 블록 크기 1, 먼저 건너뛰기SK파일의 바이트를 입력하고 복사하십시오.CT바이트를 표준 출력으로 보냅니다(또는 지정된 파일을 사용합니다
of=name
). 일반적으로 끝에 인쇄되는 상태 메시지를 방지하려면 오류 메시지를 리디렉션하세요.
답변2
이식성과 신뢰성을 고려하여 빅데이터를 변수로 저장하는 것은 좋은 생각이 아닐 수 있습니다. awk
이식하기 쉬운 비 POSIX 솔루션의 경우 sed
.
설명하다
데이터 양이 많은 경우 변수로 저장하지 마세요. 하지만Bash 자체에는 제한이 없지만 운영 체제에서는 제한이 있을 수 있습니다.
"내 운영 체제에서 작동합니다"라고 가정해 보겠습니다. 하지만,
- 운영 체제마다 제한 사항이 다릅니다.
- 따라서 이식성을 최대화하고 싶다면 왜 스크립트가 한 운영 체제에서 실행되고 다른 운영 체제에서 충돌할 위험을 감수해야 합니까?
- 따라서 처음에 변수에 저장하지 않음으로써 이 문제를 피하십시오.
그런 다음 파일에 저장합니다. 특히 문자열을 문자(또는 원하는 가장 작은 단위)와 별도의 줄로 나눕니다.
그런 다음 다음을 사용하십시오 sed
.
- sed는 전체 대용량 파일을 로드할 필요가 없으며 한 줄씩 작동합니다.
sed
POSIX 사양에 정의됨, 귀하의 요구 사항을 충족non-AWK
하지만 여전히 POSIX입니다.
또한 파일 사용의 코드 유지 관리 이점을 고려하십시오. 스크립트에서 코드를 탐색하는 것보다 파일에 저장된 줄을 업데이트하는 것이 더 쉬울 수 있습니다.
예
파일에 한 줄에 한 문자(또는 "단계별"하려는 가장 작은 단위)의 데이터가 있습니다 data.lst
.
a
b
c
d
e
다음을 포함할 수 있습니다 script.sh
.
#!/bin/bash
stop_number="$1"
sed -n "1,${stop_number}p" data.lst
따라서 명령 프롬프트에서 테스트하고 다음을 확인하세요.
$ ./script.sh 3
a
b
c
- 에서 지정한 수만큼 라인을
sed
인쇄 하는 데 사용됩니다 . 명확성을 위해 직접적으로 작성하는 대신1
$stop_number
$stop_number
$1
$stop_number
물론,$1
입력하려는 임의의 숫자인 위치 매개변수 를 통해 얻습니다.data.lst
따라서 나타나는 순서대로 3개의 문자를 성공적으로 따릅니다 .data.lst
- 이때 실제 행 수보다 큰 숫자를 입력하면 모든 행만 표시됩니다.
- 현재는
data.lst
같은 디렉토리에 있지만script.sh
원하지 않는 경우 실제로 다른 곳에 있는 경우~/some/dir/data.lst
다음과 같이 조정하면 됩니다 .~/some/dir/data.lst
따라서 실제 데이터가 있으면 data.lst
이 스크립트를 직접 테스트할 수 있습니다.
답변3
Tom에게서 조금 빌리려면:
#!/bin/sh
skp(){ dd bs="$1" skip=1 count=0; } # direct seek to target
rd (){ dd bs="$1" skip=0 count=1; } # single read at target
tail=$(sed -ne'/^don/{=;q;}' <"$0") # skip script by line#
while [ 1 -gt "$#" ] && exit # exit when args exhausted
exec <&- <"$0" || exit # exec <"$0" each iteration
do head -n "$tail" >&3 # only consider the tail
case ${2+$1} in # test args
(*[1-9]*|-*[!0]*) # skp() when ${2++} && $1 != 0
skp "$1";esac 2>&3 # send stderr to dev/null
rd "${2-$1}" 2>&3 # else just rd() from head of offset
echo; shift ${2+"2"} # append a newline and shift args away
done 3>/dev/null # put your data below this
변수에 넣지 말고 파일에 넣으십시오. 25k 변수는 쉘이 처리하기에 재미가 없으며 파일이추구싱글에서는,거의원자적 행동. 따라서 바이트 23843 - 24843을 인쇄하려면 위와 같은 작업을 수행한 후 다음을 사용하여 호출할 수 있습니다.
myscript 23843 1000
...먼저 a는 head
파일 설명자의 공유 표준에서 스크립트의 모든 줄을 제거하여 오프셋이 문자열 머리 부분에서 정확히 25k로 설정되도록 합니다. 그런 다음 첫 번째 줄 dd
은찾다오프셋은 ~23k이고 두 번째 오프셋은 dd
이를 읽습니다. 이것이 가장 간단한 방법입니다. 쉘은 문자별로 읽도록 설계되었습니다. read
예를 들어 일반적인 쉘의 내장 기능은 다음을 수행합니다.1바이트 read()
개행 문자가 발견될 때까지 반복하고 개행 문자가 발견될 때까지 멈추지 마십시오. 각 매개변수 쌍에 대해 하나의 작업이 dd
수행됩니다 .read
이것이 제가 테스트한 방법입니다:
# after a copy to my clipboard
ddscr(){ sh /tmp/ddscr.sh "$@"; }
{ xsel; man man; } > /tmp/ddscr.sh
{ echo show the size; ls -l /tmp/ddscr*
echo read from the top; ddscr 80
echo from the middle; ddscr 15k 160
echo from the tail; ddscr 64k | tail -n5
}
show the size
-rw-r--r-- 1 mikeserv mikeserv 37564 Dec 13 11:27 /tmp/ddscr.sh
read from the top
MAN(1) Manual pager utils MAN
from the middle
lso use manconv(1) directly.
However, this option allows you to convert several manual pages to a
single encoding without having
from the tail
31st March 2001 - present day: Colin Watson <[email protected]> is now
developing and maintaining man-db.
2.7.5 2015-11-06 MAN(1)
...그리고...
ddscr 10k 10 20k 10 10250 10
fi
is option
le. If
답변4
프로그램과 데이터를 동일한 파일로 감싸고 싶다면 가장 좋은 방법은 perl
. ); Windows에서는 표준으로 찾을 수 없지만 Windows에서도 찾을 수 없습니다 bash
.
#!/usr/bin/env perl
print substr(<DATA>, $ARGV[0], $ARGV[1]), "\n";
__DATA__
Just add all your text after
the __DATA__ line... no fuss, no quoting,
no tricks
예를 들어, 이름을 selected_print로 지정하고 10부터 시작하여 30자를 인쇄한다고 가정해 보겠습니다.
% selective_print 10 30