Как сделать аргументы CD без учета регистра?

9

Иногда при доступе к различным каталогам в большинстве случаев я запоминаю имена или, по крайней мере, часть имен каталогов в нашей системе Linux. Но некоторые из каталогов имеют имена, начинающиеся с заглавных букв первого символа или одного из символов в середине имени. Верхний регистр.

Может кто-нибудь предложить, как я могу сделать аргументы после cdкоманды case INSENSITIVE, чтобы, если я выполняю cd BackupDirectoryили cd backupdirectoryон мог ввести имя каталога BackupDirectory.

Конечно, я не хочу придумывать вещи для других пользователей, поэтому, если вышеприведенное возможно, возможно ли, чтобы изменения могли быть применены только к сеансу, который я использую, и не влияли бы на других пользователей?

Хорошо, я примерял, set completion-ignore-caseно это просто не работает. Это просто помогает в этом, если я набираю cd bи / Tabили Esc Escзаполняю имя каталога, игнорируя регистр. Но, что мне нужно, если я делаю cd backupdirectory, он просто игнорирует дело и входит BackupDirectoryсамостоятельно.

Анкит Вашиштха
источник
Как вы избежите двусмысленности? Если у вас есть backUPи backUpкак backupнет, в какой каталог вы хотите перейти?
Бернхард
Какую оболочку вы используете?
Герт ван ден Берг
Рассматривали ли вы использовать инструмент, как mcили переход на графический интерфейс? Делает жизнь намного проще.
ott--

Ответы:

17

Включение cdspellпоможет:

shopt -s cdspell

Со manстраницы:

cdspell Если установлено, незначительные ошибки в написании компонента каталога в команде cd будут исправлены. Проверяются ошибки: транспонированные символы, пропущенный символ и слишком много одного символа. Если исправление найдено, исправленное имя файла печатается, и команда продолжается. Эта опция используется только интерактивными оболочками.

кендырь
источник
Нужно ли что-либо делать после запуска этой команды, чтобы изменения вступили в силу?
Натан Артур
Я бы предположил, потому что простой ввод shopt -s cdspell ничего не делает для меня
sdfsdf
10

удар

set completion-ignore-case onв ~/.inputrc(или bind 'set completion-ignore-case on'в ~/.bashrc) будет моя рекомендация. Если вы собираетесь ввести полное имя, зачем нажимать Shiftклавишу несколькими нажатиями клавиши?

Но если вы действительно этого хотите, вот обертка, cdкоторая пытается найти точное совпадение, а если его нет, ищет совпадение без учета регистра и выполняет его, если оно уникально. Он использует nocaseglobопцию shell для нечувствительного к регистру глобирования и превращает аргумент в глоб, добавляя @()(что ничего не соответствует и требует extglob). extglobОпция должна быть включена при определении функции, в противном случае удар не может даже разобрать его. Эта функция не поддерживает CDPATH.

shopt -s extglob
cd () {
  builtin cd "$@" 2>/dev/null && return
  local options_to_unset=; local -a matches
  [[ :$BASHOPTS: = *:extglob:* ]] || options_to_unset="$options_to_unset extglob"
  [[ :$BASHOPTS: = *:nocaseglob:* ]] || options_to_unset="$options_to_unset nocaseglob"
  [[ :$BASHOPTS: = *:nullglob:* ]] || options_to_unset="$options_to_unset nullglob"
  shopt -s extglob nocaseglob nullglob
  matches=("${!#}"@()/)
  shopt -u $options_to_unset
  case ${#matches[@]} in
    0) # There is no match, even case-insensitively. Let cd display the error message.
      builtin cd "$@";;
    1)
      matches=("$@" "${matches[0]}")
      unset "matches[$(($#-1))]"
      builtin cd "${matches[@]}";;
    *)
      echo "Ambiguous case-insensitive directory match:" >&2
      printf "%s\n" "${matches[@]}" >&2
      return 3;;
  esac
}

Ksh

Пока я в этом, вот аналогичная функция для ksh93. ~(i)Модифицирована для случая нечувствительного соответствия кажется несовместимым с /суффиксом , чтобы соответствовать только каталогам (это может быть ошибка в моем выпуске KSH). Поэтому я использую другую стратегию, чтобы отсеять не каталоги.

cd () {
  command cd "$@" 2>/dev/null && return
  typeset -a args; typeset previous target; typeset -i count=0
  args=("$@")
  for target in ~(Ni)"${args[$(($#-1))]}"; do
    [[ -d $target ]] || continue
    if ((count==1)); then printf "Ambiguous case-insensitive directory match:\n%s\n" "$previous" >&2; fi
    if ((count)); then echo "$target"; fi
    ((++count))
    previous=$target
  done
  ((count <= 1)) || return 3
  args[$(($#-1))]=$target
  command cd "${args[@]}"
}

Zsh

Наконец, вот zsh-версия. Опять же, разрешение завершения без учета регистра, вероятно, является наилучшим вариантом. Следующая настройка возвращается к нечувствительному к регистру глобированию, если нет точного соответствия:

zstyle ':completion:*' '' matcher-list 'm:{a-z}={A-Z}'

Удалить, ''чтобы показать все регистрозависимые совпадения, даже если есть точное совпадение. Вы можете установить это из интерфейса меню compinstall.

cd () {
  builtin cd "$@" 2>/dev/null && return
  emulate -L zsh
  setopt local_options extended_glob
  local matches
  matches=( (#i)${(P)#}(N/) )
  case $#matches in
    0) # There is no match, even case-insensitively. Try cdpath.
      if ((#cdpath)) &&
         [[ ${(P)#} != (|.|..)/* ]] &&
         matches=( $^cdpath/(#i)${(P)#}(N/) ) &&
         ((#matches==1))
      then
        builtin cd $@[1,-2] $matches[1]
        return
      fi
      # Still nothing. Let cd display the error message.
      builtin cd "$@";;
    1)
      builtin cd $@[1,-2] $matches[1];;
    *)
      print -lr -- "Ambiguous case-insensitive directory match:" $matches >&2
      return 3;;
  esac
}
Жиль "ТАК - перестань быть злым"
источник
1
Это замечательно. Но вам нужно будет добавить его, чтобы inputrcон работал. Как это:echo "set completion-ignore-case on" >> ~/.inputrc
jsejcksn
@JesseJackson Да, это подразумевалось здесь, потому что спрашивающий уже знал, но я добавлю его в свой ответ для будущих посетителей.
Жиль "ТАК - перестань быть злым"
Я получаю следующую ошибку при попытке использовать cd с этим: cd:cd:17: no such file or directory: videos(у меня есть dir под названием Videos)
Sridhar Sarnobat
@ user7000 Какая версия, под какой оболочкой?
Жиль "ТАК ... перестать быть злым"
1
@ user7000 у меня работает под zsh 5.0.7. Может быть, вы установили опцию, которая меняет способ работы глобализации? Это поможет, если вы измените emulate -L zshна emulate -LR zsh? (Между прочим, я только что исправил ошибку, которая должна была emulate -L zshбыть emulate zsh, иначе это испортило бы ваши параметры оболочки.)
Жиль "ТАК - перестань быть злым"