9

Sometimes while accessing the various directories it happens most of the times that I remember the names or at least part of the names of a directory under our Linux system. But some of the directories are named starting with first character caps or one of the characters in the middle of the name Upper case.

Can anyone suggest how can I make the arguments following cd command case INSENSITIVE, such that if I perform cd BackupDirectory or cd backupdirectory it could enter the directory name BackupDirectory.

Of course I don't want to screw the things for other users so if the above is possible, is that possible that the change could be applied just to the session I am using and do not effect other users?

Ok, I tried set completion-ignore-case on but this just doesn't work. It just helps in that if I type cd b and Tab or Esc Esc it fills the directory name ignoring the case. But, what I need is if I do a cd backupdirectory, it just ignores the case and enters BackupDirectory on its own.

  • How will you avoid ambiguity? If you have backUP and backUp, how would backup no to which directory you want to go? – Bernhard Jan 3 '13 at 10:41
  • Which shell are you using? – Gert van den Berg Jan 3 '13 at 12:39
  • Have you considered using a tool like mc or switching to a GUI? Makes life much easier. – ott-- Jan 4 '13 at 20:30
16

Enabling cdspell will help:

shopt -s cdspell

From the man page:

cdspell If set, minor errors in the spelling of a directory component in a cd command will be corrected. The errors checked for are transposed characters, a miss- ing character, and one character too many. If a correction is found, the corrected file name is printed, and the command proceeds. This option is only used by interactive shells.

  • Do you have to do anything after running this command for the change to go into effect? – Nathan Arthur Jan 8 '16 at 16:00
  • I would assume so because simply entering shopt -s cdspell is not doing anything for me – MiLeung Mar 21 '17 at 5:45
10

Bash

set completion-ignore-case on in ~/.inputrc (or bind 'set completion-ignore-case on' in ~/.bashrc) would be my recommendation. If you're going to type the full name, why balk at a few presses of the Shift key?

But if you really want it, here's a wrapper around cd that tries for an exact match, and if there is none, looks for a case-insensitive match and performs it if it is unique. It uses the nocaseglob shell option for case-insensitive globbing, and turns the argument into a glob by appending @() (which matches nothing, and requires extglob). The extglob option has to be turned on when defining the function, otherwise bash can't even parse it. This function doesn't support 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

While I'm at it, here's a similar function for ksh93. The ~(i) modified for case-insensitive matching seems to be incompatible with the / suffix to match directories only (this may be a bug in my release of ksh). So I use a different strategy, to weed out non-directories.

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

Finally, here's a zsh version. Again, allowing case-insensitive completion is probably the best option. The following setting falls back to case-insensitive globbing if there is no exact-case match:

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

Remove '' to show all case-insensitive matches even if there is an exact-case match. You can set this from the menu interface of 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
    This is great. But you will need to add it to inputrc for it to work. Like this: echo "set completion-ignore-case on" >> ~/.inputrc – jsejcksn Jan 8 '16 at 4:10
  • @JesseJackson Yes, that was implicit here because the asker already knew, but I'll add it to my answer for future visitors. – Gilles Jan 8 '16 at 15:34
  • I get the following error when trying to use cd with this: cd:cd:17: no such file or directory: videos (I have a dir called Videos) – user7000 Oct 22 '16 at 19:46
  • @user7000 Which version, under which shell? – Gilles Oct 22 '16 at 19:48
  • 1
    @user7000 Works for me under zsh 5.0.7. Maybe you've set an option that changes the way globbing works? Does it help if you change emulate -L zsh to emulate -LR zsh? (By the way I just fixed a bug, that should have been emulate -L zsh, not emulate zsh, otherwise it would mess up your shell options.) – Gilles Oct 22 '16 at 23:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.