이것은 Bash와 Linux에 관한 작은 질문입니다. 등 의 특수 문자가 포함된 파일이 있습니다 \n
. \r
특수 문자를 사용하지 않고 파일을 인쇄하려고 합니다. 예를 들어, 파일 내용이 이면 hi \t hello
( 대신) 있는 그대로 인쇄됩니다 hi hello
. 사용해도 cat file
작업이 완료되지 않습니다. man of cat을 보려고 하다가 -A 옵션을 사용할 수 있다는 것을 알았습니다. 다음을 인쇄합니다: abc^Mabc
. 하지만 무엇입니까 ^M
? 표로 인쇄하려면 어떻게 해야 합니까 \<char>
?
답변1
파일에 말 그대로 이스케이프된 문자가 포함된 경우(예:"안녕하세요\n"백슬래시와 "t" 문자가 있다는 것은 탭 문자가 있어야 하고, 슬래시와 "n"이 개행 문자여야 함을 의미합니다. 그러면 이 표기법을 해석하여 실제 문자로 변환해야 합니다.
[Paul Pedant가 지적했듯이 echo를 사용한 이전 솔루션은 작동하지 않았습니다.]
몇 가지 테스트를 거친 후 Bash에서 리터럴 이스케이프 문자를 인용 해제하는 간단한 방법을 생각해 냈습니다.
x="$(cat filename)"
echo -en "$x"
작동을 확인하기 위해 이 파일을 만들었습니다(다음 cat > filename
줄을 입력한 다음 Ctrl-D
Enter
마지막 줄에 5개의 공백을 입력하고 다른 곳에 Ctrl-D
Enter
파일을 닫습니다).
This line starts with 4 leading spaces, a tab here:\t. Has a real newline (RN) here:
Newline code here:\n, six spaces and a dot: . RN:
Return code here:\r, because the return code the first three words are hidden in the terminal.RN:
This line starts with two spaces, then has four and a tab here: \tRN:
This final line ends with five spaces without an ending newline:
이 파일에 대해 위 명령을 실행하면 반환 코드로 인해 일부 줄이 덮어쓰이고 탭의 실제 너비가 표시되지 않기 때문에 터미널에 이상한 출력이 표시됩니다.
출력에서 실제 문자를 확인하려면 8진수 덤퍼에 전달하세요 od
.
x="$(cat filename)"; echo -en "$x" | od -cx
-c가 인쇄할 수 없는 이스케이프 문자를 표시하고 -x가 해당 16진수 코드(TAB=09, RETURN=0D, NEWLINE=0A, SPACE=20 등)를 표시하는 경우 결과는 다음과 같습니다.
0000000 T h i s l i n e s t
2020 2020 6854 7369 6c20 6e69 2065 7473
0000020 a r t s w i t h 4 l e a d
7261 7374 7720 7469 2068 2034 656c 6461
0000040 i n g s p a c e s , a t a
6e69 2067 7073 6361 7365 202c 2061 6174
0000060 b h e r e : \t . H a s a
2062 6568 6572 093a 202e 6148 2073 2061
0000100 r e a l n e w l i n e ( R N
6572 6c61 6e20 7765 696c 656e 2820 4e52
0000120 ) h e r e : \n N e w l i n e
2029 6568 6572 0a3a 654e 6c77 6e69 2065
0000140 c o d e h e r e : \n , s i x
6f63 6564 6820 7265 3a65 2c0a 7320 7869
0000160 s p a c e s a n d a d o
7320 6170 6563 2073 6e61 2064 2061 6f64
0000200 t : . R N : \n R e
3a74 2020 2020 2020 202e 4e52 0a3a 6552
0000220 t u r n c o d e h e r e : \r
7574 6e72 6320 646f 2065 6568 6572 0d3a
0000240 , b e c a u s e t h e r e
202c 6562 6163 7375 2065 6874 2065 6572
0000260 t u r n c o d e t h e f i
7574 6e72 6320 646f 2065 6874 2065 6966
0000300 r s t t h r e e w o r d s
7372 2074 6874 6572 2065 6f77 6472 2073
0000320 a r e h i d d e n i n t h
7261 2065 6968 6464 6e65 6920 206e 6874
0000340 e t e r m i n a l . R N : \n
2065 6574 6d72 6e69 6c61 522e 3a4e 200a
0000360 T h i s l i n e s t a r t
5420 6968 2073 696c 656e 7320 6174 7472
0000400 s w i t h t w o s p a c e
2073 6977 6874 7420 6f77 7320 6170 6563
0000420 s , t h e n h a s f o u r
2c73 7420 6568 206e 6168 2073 6f66 7275
0000440 a n d a t a b h e r e :
6120 646e 6120 7420 6261 6820 7265 3a65
0000460 \t R N : \n T h i s f i
2020 2020 5209 3a4e 540a 6968 2073 6966
0000500 n a l l i n e e n d s w i
616e 206c 696c 656e 6520 646e 2073 6977
0000520 t h f i v e s p a c e s w
6874 6620 7669 2065 7073 6361 7365 7720
0000540 i t h o u t a n e n d i n g
7469 6f68 7475 6120 206e 6e65 6964 676e
0000560 n e w l i n e :
6e20 7765 696c 656e 203a 2020 2020
0000576
아무것도 손실되지 않으며 코드는 필요한 단일 문자로 변환됩니다.
문제: Bash 변수의 최대 길이가 약 32k이기 때문에 이 간단한 작업은 작은 파일만 변환합니다. 이를 확장하려면 적절한 크기의 청크로 파일을 읽고 변환하는 루프를 만들어야 합니다. 블록 읽기의 이 부분에서 선택할 유틸리티는 입니다 dd
. 다음은 블록 크기가 16k(16384)인 이 방법을 사용하는 전체 변환기 스크립트입니다.
#!/bin/bash
# unescape.sh: converts escaped chars (\t) to actual chars (TAB)
# 2020.11.19 Fjor
#-------------------------------
[ -z "$2" ] \
&& echo "Use: $0 inputfile outputfile to unescape chars (\t -> TAB)" \
&& exit
IFILE="$1"
OFILE="$2"
#-- exists input file?
[ ! -r "$IFILE" ] \
&& echo "$0: Can't read inputfile $IFILE" \
&& exit
#-- don't destroy existing output file
[ -f "$OFILE" ] \
&& read -p "$0: Output file $OFILE exists, overwrite(s/n)? " \
&& [ x"$REPLY" != xs ] \
&& exit \
|| rm -f $OFILE
let START=0
let STEP=16384
let SIZE="$(stat -c %s $IFILE)"
let NSTEPS=SIZE/STEP+1
echo -n "Converting..."
for ((n=0 ; n<$NSTEPS ; n++)) ; do
echo -ne "\r$START bytes converted..."
#-- ibs input block size, skip N blocks, copy count blocks
x="$(dd if=$IFILE ibs=$STEP skip=$n count=1 2>/dev/null)"
echo -ne "$x" >> $OFILE
let START+=STEP
done
echo -e "\rConversion complete ($SIZE bytes)."
#-- end --#
unescape.sh
으로 저장 chmod u+x unescape.sh
하고 호출해 보겠습니다.
./unescape filename.txt outresult.txt
파일에 NULL 문자가 있으면 경고가 표시되고 NULL은 무시됩니다.