이 질문은 다음을 기반으로 합니다.Ask Ubuntu에도 비슷한 질문이 있습니다, 하지만 bash
에서 비슷한 출력을 원합니다 sh
.
Bash에는 문제가 없습니다. 예상대로 작동합니다.
wolf@linux:~$ echo $SHELL
/usr/bin/bash
wolf@linux:~$
wolf@linux:~$ varA='Aug 01
> Aug 16
> Aug 26'
wolf@linux:~$
wolf@linux:~$ varB='04:25
> 03:39
> 10:06'
wolf@linux:~$
wolf@linux:~$ echo "$varA $varB"
Aug 01
Aug 16
Aug 26 04:25
03:39
10:06
wolf@linux:~$
wolf@linux:~$ paste <(printf %s "$varA") <(printf %s "$varB")
Aug 01 04:25
Aug 16 03:39
Aug 26 10:06
wolf@linux:~$
그러나 에서 유사한 명령을 시도하면 sh
다음 오류가 발생합니다.
wolf@linux:~$ sh
$
$ varA='Aug 01
> Aug 16
> Aug 26'
$ varB='04:25
> 03:39
> 10:06'
$
$ echo "$varA $varB"
Aug 01
Aug 16
Aug 26 04:25
03:39
10:06
$
$ paste <(printf %s "$varA") <(printf %s "$varB")
sh: 22: Syntax error: "(" unexpected
$
비슷한 출력을 얻을 수 있습니까 sh
?
답변1
변수의 행 수가 동일한 경우그런 다음 이 pr
명령을 사용하여 예를 들어 표준 출력을 두 개의 열로 인쇄할 수 있습니다.
$ printf '%s\n' "$varA" "$varB" | pr -2 -Ts^I
Aug 01 04:25
Aug 16 03:39
Aug 26 10:06
탭 문자를 나타내는 ^I
(명령의 기본 구분 기호와 일치 paste
) 키 조합 Ctrl+ 소개를 사용하여 머리글과 바닥글을 V TAB동시에 닫을 수 있습니다.-T
답변2
언제든지 사용할 수 있지만 mktemp
POSIX는 이를 지정하지 않으며 이와 관련된 일부 경쟁 조건이 있습니다.
언제든지 다음과 같이 while 루프를 사용할 수 있지만 셸의 루프는 매우 느립니다.
counter=1
while true
do
left="$(echo "$varA" | awk -v cnt="$counter" 'NR==cnt {printf $0}')"
right="$(echo "$varB" | awk -v cnt="$counter" 'NR==cnt {printf $0}')"
if [ -z "$left" ] && [ -z "$right" ]
then
break
fi
echo "$left $right"
counter=$((counter + 1))
done
산출:
Aug 01 04:25
Aug 16 03:39
Aug 26 10:06
필요한 경우 더 많은 변수를 추가할 수 있지만 만족스럽지 않습니다. 동적 변수 수에 대해 작동해야 함수동으로 추가해야 하기 때문에 필요합니다. 물론 awk로 모든 것을 구현할 수 있습니다.
답변3
현상금 공지에는 다음과 같은 내용이 나와 있습니다.
대답은 줄 수가 다른 변수에 대한 모든 쉘에서 작동해야 하며 동적 변수 수에 대해 작동해야 합니다.
엄밀히 말하면 "모든 쉘에서 작업"하는 것은 불가능합니다. 거의 할 수 없는 일이에요아무것C 쉘 계열의 쉘과 Bourne 쉘/POSIX 쉘 계열에서 작업하는 것이 매우 중요합니다. 나는 bash, dash(상당히 기본적인 POSIX 호환 셸), ash 및 zsh에서 다음을 테스트했습니다.
여러 줄 변수를 설정하는 몇 가지 방법은 다음과 같습니다.
var17='The
quick
brown
fox'
var42=`echo jumps; echo over; echo -e 'the\nlazy\ndog.'`
another_var=$(printf '%s\n' And they lived happily ever after.)
yet_another=$'The\nend.'
첫 번째 방법(실제로 Enter따옴표 안에 입력)은 전부는 아니더라도 대부분의 POSIX 호환 쉘에서 작동합니다 1 . 두 번째 접근 방식( )은 전부는 아니지만 대부분의 POSIX 호환 쉘 2 에서 작동하지만 ) 부분은 그렇지 않을 수도 있습니다. 일부 오래된 쉘은 인식되지 않을 수 있으며 (완전히?) bashism입니다.`echo word1 ; echo word2`
echo -e 'word3\nword4'
$(…)
$'…'
솔루션이 패턴을 따르는 변수 이름에 의존하지 않는다는 것을 보여주기 위해 의도적으로 일관된 패턴이 없는 변수 이름을 사용합니다. 필요한 경우 varA
, varB
, varC
및 varD
(또는 var1
, var2
, var3
및 )를 사용할 수 있습니다.var4
솔루션을 실행하십시오.
$ ./myscript1 "$var17" "$var42" "$another_var" "$yet_another"
The jumps And The
quick over they end.
brown the lived
fox lazy happily
dog. ever
after.
분명한 사실은 문자열의 줄 수가 다르고 줄의 문자 수가 다르다는 것입니다. 우리는하지 않습니다~ 해야 하다 변수를 사용하면 명령줄에 직접 여러 줄의 문자열 값을 입력할 수 있습니다.
$ ./myscript1 "$var17" "$var42" "$another_var" $'The\nend.'
The jumps And The
quick over they end.
brown the lived
fox lazy happily
dog. ever
after.
이것은 myscript1
:
#!/bin/dash
first=1
for a in "$@"
do
if [ "$first" = 1 ]
then
set --
first=
fi
file=`mktemp`
set -- "$@" "$file"
printf '%s\n' "$a" > "$file"
done
pr -T -m "$@"
rm "$@"
노트:
- 많은 POSIX 호환 쉘에는 명명된 배열이 없으므로 모두 지원하는 하나의 (이름이 지정되지 않은) 배열인 인수 목록을 사용합니다.
for a in "$@"
루프에 들어가면 ,그것은값 목록은 쉘의 인수 목록을 변경할 수 있도록 설정됩니다.- 첫 번째 단계에서는 손상된 쉘의 매개변수 목록이 사용됩니다
set --
. - 지나갈 때마다,
- 임시 파일을 만듭니다. 이식성을 높이기 위해
`mktemp`
대신 사용하십시오$(mktemp)
(그렇지 않으면$(…)
일반적으로 선호됨). - 매개변수 목록에 파일 이름을 추가합니다.
- 현재 매개변수를 씁니다(예:원래매개변수 목록)을 파일에 추가합니다.
printf
이것이 모든 쉘에서 내장 명령으로 사용 가능한지는 모르겠지만 ,쓸 수 있는 (내장 명령 또는 외부 실행 프로그램으로) 박물관 외부의 모든 시스템에 설치됩니다. 시스템에 없으면printf
사용해 볼 수 있지만echo
다음으로 시작하는 문자열에 주의하세요.-
또는 포함합니다\
.
- 임시 파일을 만듭니다. 이식성을 높이기 위해
pr
파일 목록에서 호출됩니다.-T
페이징을 방지하려면 Steeldriver OK를 사용하십시오 .- 파일 병합 용
-m
(예: 다중 열 모드)
- 마지막으로 모든 파일을 삭제합니다.
이는 열이 많은 공백으로 구분된 것처럼 보이지만 항상 그런 것은 아닙니다.
$ ./myscript1 "A very long string about a quick brown fox and a lazy dog" .
A very long string about a quick br .
일어나는 일은 다음과 같습니다.
pr
파일 수, 즉 열 수를 계산합니다. 그렇게 부르자명사- 선 너비를 다음으로 나눕니다.,반올림합니다. (줄 너비는 기본적으로 72입니다.)
- 그것은 창조한다N열, 각 열 ⌊ 72/N ⌋ 문자 위치가 넓어졌습니다. 이보다 좁은 값은 채워지고, 이보다 넓은 값은 잘립니다.
공백과 잘림을 피하는 것이 좋습니다. pr
다음 옵션을 사용하여 선 너비를 지정할 수 있기 때문에 이를 수행할 수 있습니다 -w
.
$ ./myscript2 "A very long string about a quick brown fox and a lazy dog" .
A very long string about a quick brown fox and a lazy dog .
이것은 myscript2
:
#!/bin/dash
if [ "$#" = 0 ]
then
printf '%s\t%s\n' "Usage:" "$0 [string] ..."
exit 1
fi
first=1
maxwidth=0
for a
do
if [ "$first" = 1 ]
then
set --
first=
fi
file=`mktemp`
set -- "$@" "$file"
printf '%s\n' "$a" > "$file"
width=`printf '%s\n' "$a" | wc -L`
if [ "$width" -gt "$maxwidth" ]
then
maxwidth="$width"
fi
done
linewidth=`expr "$#" "*" "(" "$maxwidth" + 2 ")"`
pr -T -w "$linewidth" -m "$@"
rm "$@"
노트:
for a
응 줄임말for a in "$@"
. 이는 ash, bash, dash, zsh 및 기타 시스템에서 작동합니다.wc -L
입력에서 최대 줄 길이를 찾으십시오. 불행하게도 이것은 GNU 확장입니다. 이는 POSIX 도구를 사용하여 수행할 수 있지만 그렇게 간단하지는 않습니다.- 모든 입력에서 가장 긴 줄을 찾기 위해 반복합니다.
- … 그런 다음 수용할 수 있을 만큼 큰 선 너비를 계산합니다.N 해당 너비의 열에 열 구분을 위한 공백 2개를 더한 것입니다.
____________
1그러나\ 앞에 a를 입력하지 않으면 C 쉘은 이를 허용하지 않습니다 Enter.
2 C 셸에서는 이를 허용하지만 개행 문자를 공백으로 변환합니다. (제가 놓친 부분이 있을 수도 있습니다.)
답변4
1. 명령paste
paste /dev/fd/3 3<<-EOF /dev/fd/4 4<<-EOF
> $varA
> EOF
> $varB
> EOF
산출:
Aug 01 04:25
Aug 16 03:39
Aug 26 10:06
또는 임시 파일과 함께 붙여넣기를 사용할 수 있지만 프로세스가 오래 걸립니다.
temp_file=$(mktemp)
2. 명령pr
printf '%s\n' "$varA" "$varB" | pr -2 -t -s
산출:
Aug 01 04:25
Aug 16 03:39
Aug 26 10:06