Считайте и обработайте строку, символ символом, все же позвольте пользователю простому редактированию строки вход

Я предполагаю, что Вы видите это недопустимый символ, потому что имя содержит последовательность байта, которая не является допустимым UTF-8. Имена файлов в типичных файловых системах Unix (включая Ваш) являются строками байтов, и это до приложений для выбора что кодирование использовать. В наше время существует тенденция для использования UTF-8, но это не универсально, особенно в локалях, которые никогда не могли жить с плоскостью ASCII и использовали другую кодировку прежде, чем UTF-8 даже существовал.

Попробовать LC_CTYPE=en_US.iso88591 ls видеть, имеет ли имя файла смысл в ISO-8859-1 (латинский 1). Если это не делает, попробуйте другие локали. Отметьте это только LC_CTYPE установка локали имеет значение здесь.

В локали UTF-8 следующая команда покажет Вам всем файлы, имя которых не является допустимым UTF-8:

grep-invalid-utf8 () {
  perl -l -ne '/^([\000-\177]|[\300-\337][\200-\277]|[\340-\357][\200-\277]{2}|[\360-\367][\200-\277]{3}|[\370-\373][\200-\277]{4}|[\374-\375][\200-\277]{5})*$/ or print'
}
find | grep-invalid-utf8

Можно проверить, имеют ли они больше смысла в другой локали с перекодом или iconv:

find | grep-invalid-utf8 | recode latin1..utf8
find | grep-invalid-utf8 | iconv -f latin1 -t utf8

После того как Вы решили, что набор имен файлов находится в определенном кодировании (например, latin1), один способ переименовать их

find | grep-invalid-utf8 |
rename 'BEGIN {binmode STDIN, ":encoding(latin1)"; use Encode;}
        $_=encode("utf8", $_)'

Это использует жемчуг, переименовывают команду, доступную на Debian и Ubuntu. Можно передать его -n показать то, что это обошлось бы без фактического переименования файлов.

5
08.08.2011, 16:38
3 ответа

Если Вы читаете символ за один раз с read -n, необходимо будет реализовать синтаксический анализатор сочетания клавиш. Можно создать медленное-и-грязное решение, которое работает над большинством терминалов с этим: полагайте, что escape-последовательность функциональной клавиши начинается с символа ESC и продолжает любое количество символов среди 0-9;[]O сопровождаемый одним последним символом не в этом наборе.

Лучший способ считать вход состоит в том, чтобы пользоваться надлежащей входной библиотекой. Bash использует один в его собственных целях (readline). Вы получаете ограниченный интерфейс к нему путем объявления собственных привязок клавиш с bind встроенный; конкретно bind -x выполнять команду оболочки на нажатии клавиши. Из-за этого ограниченного интерфейса реализовывая то, что Вы хотите, вероятно, будет возможно, но трудно.

Zsh имеет свою собственную входную библиотеку, zle. Его интерфейс намного более богат, чем удар. С zle можно определить произвольные контурные карты, и Вы получаете больше доступа к внутренностям zle из кода оболочки. Использовать zle присваивать оболочку функционирует к zle пользовательским командам (названный виджетами), bindkey создать и заполнить Вашу собственную контурную карту, и наконец vared считать строку входа с помощью контурной карты по Вашему выбору.

3
27.01.2020, 20:39
  • 1
    я все еще корплю в этом.. Это - "интересная" кривая обучения по меньшей мере. Мне удалось добраться read -n метод, работающий достаточно хорошо, но я сейчас понял это tmux и screen используйте различные привязки клавиш для ДОМА и КОНЦА, чем делают konsole и gnome-terminal без мультиплексоров... Возможно, это - emacs по сравнению с vi проблемой привязки клавиш... Я добираюсь там, и 'readline' метод начинает иметь некоторый смысл мне теперь, но я должен придерживаться с read -n 1 на данный момент. Это достаточно довольно быстро (но медленно для записи :). Когда я закончил, я далее посмотрю на readline. –  Peter.O 09.08.2011, 22:33
  • 2
    @fred Различные терминалы с помощью различных escape-последовательностей (иногда тот же терминал будет использовать другую последовательность в полноэкранном режиме и режиме строки) является фактом жизни. Это - одна из причин пользоваться библиотекой, где кто-то уже сделал работу для Вас. К счастью, нет никакого перекрытия среди общих терминалов (т.е. если последовательность соответствует определенному ключу на определенном терминале, она не соответствует, другой включает другой терминал). –  Gilles 'SO- stop being evil' 09.08.2011, 22:43

Можно поместить терминал в режим без предварительной обработки после первого read если существует esc символ, и затем использует секунду read считать и проанализировать остающиеся байты если любой (cf. Травма символа ESC Bash и видит также arrows.txt).

#!/bin/bash

# tested on Mac OS X 10.6.8

IFS=$'\n'
old_tty_settings="$(stty -g)"
exec 0</dev/tty

tput smir  # enable insert mode

while IFS="" read -r -s -n1 key; do    # first read (reads only a single byte)

#od -c <<<"$key"
#continue

((${#key}==0)) && break

case "$key" in
  $'\001')  printf '\r'                          #  ctrl-a
            continue;;   
  $'\177')  tput rmir 
            printf "\010\040\010\033[P"          # backspace
            tput smir
            continue;;                          
  $'\025')  printf "\033[1K"                     # tput el1 does not work on Mac OS X 10.6.8 
            continue;;                           # ctrl-u  (clear to start of line)
  $'\v')    tput el
            continue;;                           # ctrl-k  (clear to end of line)
esac

# if the first char is esc (i.e. \e or \033 respectively)
if [[ "$key" == $'\033' ]]; then    

  stty cbreak -echo min 0 time 0   # set raw terminal 

  IFS="" read -r bytes     # second read (reads remaining bytes)

  if [[ ${#bytes} -gt 0 ]]; then

     stty "$old_tty_settings"

     case "${key}${bytes}" in 
       $'\033[3~')   tput dch1         # delete one char
                     continue;; 
     esac

     printf "${key}${bytes}"

  else
     stty "$old_tty_settings"
  fi

 else

  #stty "$old_tty_settings"
  printf '%s' "$key"

fi

done

echo

exit 0
2
27.01.2020, 20:39

Взгляните на селектор инструмента командной строки.

# usage examples
selector -v -x @ <(find . -maxdepth 2 -type d | awk '{print $0"@cd "$0}')
selector -v -x @ <(grep -E -o 'http[^ ]+' fileWithURLS)
1
27.01.2020, 20:39

Теги

Похожие вопросы