Как удалить несколько специальных символов из файла?

Как удалить несколько специальных символов из файла?

Скрипт ниже в настоящее время удаляет символ ^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 liner. '\cM' — это символ control-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

Связанный контент