해결책을 찾으려고 노력 중이에요이것질문. 지금까지 이 문제를 해결한 방법은 다음과 같습니다.
- 모든 문자를 함께 추가하여 하나의 긴 문자열을 만듭니다.
- 위 단계를 완료한 후 공백이나 탭 공백을 모두 제거하여 하나의 큰 문자열만 남게 합니다.
다음 명령을 사용하여 위 단계를 빌드할 수 있었습니다.
column -s '\t' inputfile | tr -d '[:space:]'
따라서 이와 같은 입력 파일의 경우
1 0 0 0 0 0
0 1 1 1 0 0
위 명령을 적용한 후 내 값은 다음과 같습니다.
100000011100
이제 이 큰 문자열에 다음과 같은 방법을 적용해 보겠습니다.
원래 OP에서 요구하는 대로 모든 6 자를 추출하여 문자열 끝까지 배열 요소에 추가합니다.
따라서 기본적으로 위의 단계를 통해 다음과 같이 배열 요소를 생성하려고 합니다.
10
( 1번째 와 7번째 문자), ( 2번째01
와 8번째 문자 ), (3번째 와 9번째 문자), (4번째 와 10번째 문자), ( 5번째 와 11번째 문자 ), ( 6번째 와 12번째 문자) 첫 번째 문자).01
01
00
00
그래서 내 질문은, 추가 처리를 위해 배열에 추가할 수 있도록 모든 n 문자를 어떻게 추출할 수 있습니까? (이 경우 n=6).
답변1
두 줄
bash
배열 을 생성 bash
하는 순수한 솔루션은 다음과 같습니다 .
s="100000011100"
array=($(
for ((i=0; i<${#s}-6; i++))
do
echo "${s:$i:1}${s:$((i+6)):1}"
done
))
echo "${array[@]}"
그러면 질문에 표시된 것과 동일한 출력이 생성됩니다.
10 01 01 01 00 00
여기서 핵심 요소는 bash를 사용하는 것입니다.하위 문자열 확장. Bash를 사용하면 parameter
via 와 같은 변수에서 하위 문자열을 추출할 수 있습니다 ${parameter:offset:length}
. 우리의 경우 오프셋은 루프 변수에 의해 결정되며 i
길이는 항상 입니다 1
.
모든 라인 수에 대한 범용 솔루션
예를 들어 원래 문자열이 18자라고 가정하면 i의 i번째, i+6번째, i+12번째 문자를 0에서 5까지 추출하려고 합니다. 그래서:
s="100000011100234567"
array=($(
for ((i=0; i<6; i++))
do
new=${s:$i:1}
for ((j=i+6; j<${#s}; j=j+6))
do
new="$new${s:$j:1}"
done
echo "$new"
done
))
echo "${array[@]}"
그러면 다음과 같은 출력이 생성됩니다.
102 013 014 015 006 007
동일한 코드를 6자 라인으로 확장할 수 있습니다. 예를 들어 s
세 줄(18자)이 있는 경우:
s="100000011100234567abcdef"
그러면 출력은 다음과 같습니다.
102a 013b 014c 015d 006e 007f
답변2
사용 perl
:
$ echo 100000011100 | perl -nle '
for ($i = 0; $i < length()/2; $i++) {
print substr($_,$i,1), substr($_,$i+6,1);
}
'
10
01
01
01
00
00
두 라인 모두에서 작동합니다. 임의의 행을 처리하려면 큰 문자열을 작성하는 대신 행을 직접 처리해야 합니다. 다음 입력을 전달하세요.
1 0 0 0 0 0
0 1 1 1 0 0
0 0 0 0 0 0
노력하다:
$ perl -anle '
for ($i = 0; $i <= $#F; $i++) {
push @{$h{$i}}, $F[$i];
}
END {
print @{$h{$_}} for keys %h;
}
' file
000
010
000
100
010
010
답변3
쉘 솔루션으로서 getopts
아마도 가장 간단할 것입니다. 문제는 getopts
POSIX가 지정되어 있고 정확히 원하는 작업을 수행한다는 것입니다. 즉, 쉘 루프에서 바이트 스트림을 처리합니다. 이상하게 들린다는 걸 알아요. 제가 이 말을 배우기 전에 여러분도 저와 같다면 다음과 같이 생각할 수도 있으니까요.글쎄요, 저는 그것이 명령줄 스위치를 처리해야 한다고 생각했습니다.이것은 사실이지만 첫 번째도 마찬가지입니다. 고려하다:
-thisisonelongstringconsistingofseparatecommandlineswitches
예, getopts
이 문제를 해결해야 합니다. 루프에서 문자별로 분할하고 $OPTARG
쉘 변수 또는 이름으로 지정한 다른 변수의 각 문자를 반환해야 하며, 이는 호출할 때 얼마나 구체적으로 얻는지에 따라 다릅니다. 더 중요한 것은 쉘 변수에 오류를 반환해야 한다는 것입니다.진행 상황을 저장하다쉘 변수에서 실행될 때 $OPTIND
,중단한 부분부터 계속어떻게든 해결이 가능하다면. 하위 쉘을 호출하지 않고 전체 작업을 완료해야 합니다.
다음과 같은 결과가 있다고 가정합니다.
arg=$(seq -s '' 1000); set --
while getopts :0123456789 v -"${arg}"
do [ "$((i=$i+1<6?$i+1:0))" -gt 0 ] ||
set "$@" "$v"
done
흠... 작동하는지 궁금해요?
echo "$((${#arg}/6))" "$#"
482 482
괜찮아...
eval '
printf %.1s\\n "${arg#'"$(printf %0$((124*6-1))d | tr 0 \?)"'}" "${124}"'
4
4
따라서 보시다시피 이 getopts
명령은 문자열의 6바이트마다 배열을 완전히 설정합니다. 이와 같은 숫자일 필요는 없으며 심지어 쉘 안전 문자일 수도 있습니다. 위에서 했던 것처럼 대상 문자를 지정할 필요도 없습니다 01234565789
. 나는 이것을 많은 쉘에서 반복적으로 테스트했으며 모두 잘 작동합니다. 몇 가지 특이한 점이 있습니다. bash
첫 번째 문자가 공백 문자이면 버려집니다. 콜론 은 POSIX에서 명시적으로 금지하는 유일한 인수임에도 불구하고 지정된 인수로 dash
허용됩니다 . :
하지만 문제가 되지 않습니다. 오류를 반환하더라도 getopts
현재 opt char 값은 계속 저장되기 때문입니다.$OPTARG
(지정한 opt 변수에 할당된 ?로 표시됨)$OPTARG
그렇지 않으면 옵션에 인수가 있어야 한다고 선언하지 않는 한 명시적으로 설정이 해제됩니다 . 공백은 좋은 것입니다. 공백은 하나만 버립니다.선두알 수 없는 값을 처리할 때 다음과 같이 할 수 있기 때문에 좋습니다.
getopts : o -" $unknown_value"
...첫 번째 문자가 실제로 허용하는 args 문자열에 있을 위험 없이 루핑을 시작합니다. 이렇게 하면 getopts
전체 내용이 $OPTARG
한 번에 인수로 삽입됩니다.
또 다른 예는 다음과 같습니다.
OPTIND=1
while getopts : o -" $(dd if=/dev/urandom bs=16 count=1 2>/dev/null)"
do printf '\\%04o' "'$OPTARG"; done
\0040\0150\0071\0365\0320\0070\0161\0064\0274\0115\0012\0215\0222\0271\0146\0057\0166
$OPTIND=1
방금 사용했기 때문에 첫 번째 줄에 설정했으며 , getopts
재설정하기 전에 다음 호출이 중단된 부분부터 계속되기를 기대합니다. "${arg2}"
즉, 원하는 것입니다. 하지만 주고 싶지 않고 지금은 다른 일을 하고 있어서 $OPTIND
언제 시작할 수 있는지 알려드리기 위해 재설정했습니다.
내가 사용한 이 문자에서는 zsh
선행 공백에 반대하지 않습니다. 따라서 첫 번째 문자는 8진수 40 공백 문자입니다. 하지만 저는 보통 getopts
이런 식으로 사용하지 않습니다. 주로 사용합니다.피하다write()
위에서 했던 것처럼 각 바이트에 대해 작업을 수행 하고 해당 출력(변수의)을 다른 쉘 변수에 할당합니다 set
. 그런 다음 준비가 되면 전체 문자열을 가져올 수 있으며, 그렇게 하면 일반적으로 첫 번째 바이트가 제거됩니다.
답변4
sed
내 마음에 가장 먼저 떠오른 것은.
$ echo 1234567890abcdefghijklmnopqrstuvwxyz | sed 's/.\{5\}\(.\)/\1/g'
6bhntz
5개의 문자를 일치시키고, 6번째 문자를 캡처하고, 모두 캡처된 문자로 대체합니다.
그러나 문자열 길이가 정확히 6의 배수가 아닌 경우 문제가 발생합니다.
$ echo 1234567890abcdefghijklmnopqrstuvwxy | sed 's/.\{5\}\(.\)/\1/g'
6bhntuvwxy
하지만 sed
다음과 같이 약간 변경하면 이 문제를 해결할 수 있습니다.
$ echo 1234567890abcdefghijklmnopqrstuvwxy | sed 's/.\{1,5\}\(.\{0,1\}\)/\1/g'
6bhnt
정규식의 욕심 많은 특성으로 인해 가능하면 가변 길이 일치가 일치하고, 캡처할 항목이 남아 있지 않으면 캡처되지 않고 문자가 제거됩니다.