파일에서 여러 특수 문자를 제거하는 방법은 무엇입니까?

파일에서 여러 특수 문자를 제거하는 방법은 무엇입니까?

아래 스크립트는 현재 ^M 문자( Ctrl+V+M)를 제거합니다. 좀 장황한 것 같지만 ^I와 앞으로 볼 수 있는 다른 문자도 추가해야 합니다.

^I( )를 추가하는 더 쉬운 방법이 있나요 Ctrl+V+I? 이것은 약 6개월 전에 2일간의 쉘 프로그래밍 과정을 수강한 후 제가 직접 작성한 첫 번째 스크립트입니다. 필요한 것보다 시간이 더 오래 걸리는지 잘 모르겠으므로 일반적인 팁도 알려주시면 감사하겠습니다.

#!/bin/bash  

    echo "$# item(s) to review."
    question='Do you want to remove the ^M characters?'

    for file
    do
            if grep "^M" "$file" >> /dev/null 2> /dev/null
            then
                    echo "$file contains special characters"
                    echo $question
                    read answer
                            if    [[ "$answer" == [yY] ]]
                            then
                                    cat "$file" | sed "s/^M//" > "$file.safe"
                                    echo "Special characters have been removed and $file.safe has been created."
                            elif  [[ "$answer" == [yY][eE][sSaA]* ]]
                            then
                                    cat "$file" | sed "s/^M//" > "$file.safe"
                                    echo "Special characters have been removed and $file.safe has been created."
                            else
                                    echo "Special characters have NOT been removed."
                            fi
            elif [[ -d $file ]]
            then
                    echo "$file is a directory"
            else
                    echo "No special characters in $file"
            fi
    done

답변1

확실히 필요한 것보다 훨씬 더 오래 걸렸습니다. 당신에게 필요한 것은tr유용, 스크립트에 인수로 전달된 파일에 대해 작동하는 루프 및 리디렉션이 포함됩니다.

#!/bin/sh
for file do
  tr -d '\r\t' <"$file" >"$file.safe"
done

옵션을 사용하여 지정된 문자를 삭제 -d합니다 tr. 제거할 문자는 옵션이 아닌 첫 번째 인수로 함께 전달됩니다. 백슬래시 이스케이프를 사용하여 \n개행(^J), \r캐리지 리턴(^M), \t탭(^I) 등 특수 문자를 나타낼 수 있습니다.

사용자에게 묻는 코드는 말이 안 되기 때문에 복사하지 않았습니다. 어쨌든 디렉토리는 리디렉션 오류를 일으키고 디렉토리를 일반 파일로 처리하는 것과 같은 무의미한 작업을 실제로 요청하지 않는 것이 호출자의 임무이므로 해당 부분도 건너뛰었습니다.

원본 파일을 바꾸려면 임시 파일에 쓴 다음 결과를 제자리로 옮깁니다.

#!/bin/sh
for file do
  tmp="$(TMPDIR=$(dirname -- "$file") mktemp)"
  tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file"
done

임시 파일 이름은 mktemp스크립트를 더욱 강력하게 만들기 위해 구성됩니다. 파일이 포함된 디렉터리에 대한 쓰기 액세스 권한이 있는 한 기존 파일을 덮어쓸 위험 없이 작동합니다. 다른 데이터를 삽입하려고 시도하는 다른 사용자가 해당 디렉토리에 쓸 수 있더라도(참조 자료의 잠재적인 문제 /tmp) 안전합니다.

mv이 명령은 호출이 성공한 경우에만 호출되므로 tr실패해도 데이터가 손실될 위험이 없습니다(예: 디스크가 가득 찬 경우).tr

파일을 특수 문자가 포함되지 않은 동일한 새 파일로 바꾸는 것을 방지하려면 다음 두 가지 방법이 있습니다.

  • 특수 문자를 먼저 확인할 수 있습니다. 이를 수행하는 방법에는 여러 가지가 있습니다. 한 가지 방법은 특수 문자를 제외한 모든 문자를 제거하고 결과 문자 수를 계산하는 것입니다. 최적화로서 head -c 1특수 문자가 상단 근처에서 발견되면 전체 파일을 검토할 필요가 없도록 파이프하십시오. 이렇게 하면 할 일이 없으면 개수는 0이고 그렇지 않으면 1입니다.

    if [ "$(tr -dc '\r\t' <"$file" | head -c 1 | wc -c)" -ne 0 ]; then
      tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file"
    fi
    
  • 변환한 후 원본 버전과 동일한지 확인할 수 있습니다. 일반적으로 파일이 이미 원하는 상태에 있는 경우 속도가 느려질 수 있습니다. 반면, 이 기술은 파일이 원하는 상태인지 판단하기가 쉽지 않은 상황에 적합합니다.

    tr -d '\r\t' <"$file" >"$tmp" &&
    if cmp -s "$tmp" "$file"; then
      rm -- "$tmp"
    else
      mv -f -- "$tmp" "$file"
    fi
    

답변2

스크립트 주위에 루프를 넣을 수 있습니다. 그래서:

 for c in "^I" "^M"; do
    for file; do
       if grep "$c" "$file"; then
          ...
          etc.
          ...
       fi
    done
 done

답변3

나는 이 Perl One 라이너를 선호합니다. '\cM'은 제어 M 문자입니다. 원본 파일은 ".bak" 확장자로 백업됩니다. 이 확장은 귀하가 선택할 수 있습니다.

perl -i.bak -pe 's/\cM//g;'  file(s)

제거할 문자 유형을 사용하는 예입니다. 괄호 안에서 perl은 control-I와 control-M을 찾아서 제거합니다. 하지만 아직 구체적으로 테스트하지는 않았습니다.

perl -i.bak -pe 's/[\cM\cI]//g;' files(s)

답변4

사용에 대해 생각해 본 적이 있습니까?

 tr -d .....<characterlist>....

예를 들어 인쇄할 수 없는 문자를 모두 제거하고 다른 파일에 넣으세요.

 cat filename | tr -cd '[:print:]' >/tmp/x.out

응용 프로그램에 맞게 문자 목록을 수정하십시오. tr자세한 내용은 매뉴얼 페이지를 참조하십시오.

정규식 범위가 허용되기 때문에 이는 또한 좋습니다.

 echo '\001\002\003\004' | tr -d '[\001-\003]' | od -c

관련 정보