10

I just upgraded my Ubuntu 16.04 to 17.04 and found a little problem with cd command.

Let's say that I have two folders: album-01 & album-02

In Ubuntu 16.04, if I do cd album* it will go to the first folder found album-01

But in new Ubuntu 17.04, if I do cd album* it result me -bash: cd: too many arguments

How to make cd in Ubuntu 17.04 like cd in Ubuntu 16.04?

  • 4
    What you get does make sense, as you give cd two locations, and somehow expect it to figure out which one you want. – mikewhatever Apr 17 '17 at 14:21
  • 1
    @mikewhatever Unfortunately, the Bash manual disagrees with you: "Any additional arguments following directory are ignored" – muru Apr 18 '17 at 2:52
  • 3
    Posted a bug report, in case anyone's interested: bugs.launchpad.net/ubuntu/+source/bash/+bug/1683576 – muru Apr 18 '17 at 3:09
  • Please don't forget to accept the answer that helped you most by clicking the grey round check button on its left, if your question is solved satisfyingly. – Byte Commander Apr 18 '17 at 12:05
9

I couldn't test this on a real 17.04 system yet (only verified that it works on 16.04), but you should be able to override the cd Bash built-in command with your own custom function, which discards any additional arguments except the first one:

cd(){ command cd "$1" ; }

Update: As suggested in @muru's comment, this version below might work better and support calling cd without arguments though:

cd(){ builtin cd "${@:1:1}"; }

After you have entered this line above in your terminal, please verify whether cd now behaves in the way you want. If this is the case, you can make this function definition persistent by appending that line to the end of your ~/.bashrc file. Otherwise it will vanish as soon as you end your current shell session.

Note that if for whatever reason you temporarily need to use the real cd Bash built-in command instead of this custom function, you can simply call it with command cd instead of plain cd.

  • I was writing the same thing, instead of function I was suggesting an alias to tiny script... sure it works ;) – Ravexina Apr 17 '17 at 14:50
  • @Ravexina I considered using an alias first too, but then dropped that because I think it can't be done with an alias, because there you don't have control overt the arguments. Just out of curiosity, what approach would you have suggested? – Byte Commander Apr 17 '17 at 14:52
  • I did the same thing, I just put the code in a .sh file then created an alias like: mcd="source /home/user/bin/cd.sh" – Ravexina Apr 17 '17 at 14:54
  • Ah, ok. That is a bit more complicated than it would need to be, but should work as well. – Byte Commander Apr 17 '17 at 14:56
  • 2
    @SandiHidayat Try cd () { builtin cd "${@:1:1}"; } instead. – muru Apr 18 '17 at 9:12
7

Short answer/Workaround

To answer your question in this exact case, this works

cd album*1

But it is probably not the functionality you really want.

What changed?

It appears that config-top.h in Bash-4.4 was updated to add the following option

/* Define CD_COMPLAINS if you want the non-standard, but sometimes-desired
   error messages about multiple directory arguments to `cd'. */

#define CD_COMPLAINS

And builtins/cd.def refers to your error here:

#if defined (CD_COMPLAINS)
  else if (list->next)
    {
      builtin_error (_("too many arguments"));
      return (EXECUTION_FAILURE);
    }
#endif

What can I do long-term?:

You could compile your own bash without the new CD_COMPLAINS, but that would get tedious. You can redefine the cd functionality like suggested here or you could alias a function like

cd "$(find $1* | head -1)"

Proving it

Bash 4.4 Beta where it still works

#Pulling and unpacking source
$ wget https://ftp.gnu.org/gnu/bash/bash-4.4-beta.tar.gz
$ tar -xzvf bash-4.4-beta.tar.gz
$ cd bash-4.4-beta

#Building, go grab something to drink. It's gonna be a while.
~/bash-4.4-beta$ ./configure
~/bash-4.4-beta$ make

#Check Version
~/bash-4.4-beta$ ./bash --version
GNU bash, version 4.4.0(1)-beta (x86_64-unknown-linux-gnu)

#Enter a clean interactive prompt
~/bash-4.4-beta$ env -i PATH="$PWD:$PATH" ./bash --noprofile --norc

#Test example
bash-4.4$ mkdir album-0{1..2}
bash-4.4$ cd album* && pwd
/home/gkent/bash-4.4-beta/album0-1

Bash 4.4 Stable Release where it doesn't work

#Pulling and unpacking source
$ wget https://ftp.gnu.org/gnu/bash/bash-4.4.tar.gz
$ tar -zxvf bash-4.4.tar.gz
$ cd bash-4.4/

#Building, go grab something to drink. It's gonna be a while.
~/bash-4.4$ ./configure
~/bash-4.4$ make

#Check Version
~/bash-4.4$ ./bash -version
GNU bash, version 4.4.0(1)-release (x86_64-unknown-linux-gnu)

#Enter a clean interactive prompt
~/bash-4.4$ env -i PATH="$PWD:$PATH" ./bash --noprofile --norc

#Test example
bash-4.4$ mkdir album-0{1..2}
bash-4.4$ cd album*
bash: cd: too many arguments
  • Sorry, was a typo. Updated answer. – Grayson Kent Apr 17 '17 at 19:52
  • Ah, right. You could just do cd alb*1, to match the literal 1 at the end even without the brackets. I confused your idea with something else at first. – ilkkachu Apr 17 '17 at 20:54
4

I've never encountered this issue as I always use Tab Completion.

So in your case, rather than having an imprecise guess as to which directory I want, I would type cd alTab which if there's only one match, completes it and if there are 2 or more completes up to where the matching ends and TabTab lists the choices.

Here's an example from my system:

cd Un Tab

cd Unknown

followed by TabTab produces

Unknown/                        Unknown Artist - Unknown Album/ 
2

This looks like a bug in Bash: per man builtins the old behaviour is the correct one.

   cd [-L|[-P [-e]] [-@]] [dir]
              Change the current directory to dir.  if dir is not supplied,
              the  value  of  the  HOME shell variable is the default.  Any
              additional arguments following dir are ignored.

You can report the bug on the bug-bash mailing list; more details here.


Actually, the bug was reported (long ago). If you want a fixed Bash now, now, now, here's how to do it properly (tested on 17.10, should work on others as well).

First create a directory to work in, for example:

mkdir ~/bash
cd ~/bash

Get the source package and the build dependencies:

apt-get source bash
sudo apt-get build-dep bash
cd bash-4.4

Edit config-top.h to change this (should be line 32)

#define CD_COMPLAINS

to this

/* #define CD_COMPLAINS */

Edit debian/changelog and add an entry like this at the top (you can also use the command dch -i):

bash (4.4-5ubuntu1+cd) artful; urgency=medium

  * Fix cd.

 -- Firas Kraiem <firas@fkraiem.org>  Thu, 04 Jan 2018 21:11:22 +0900

The most important points are to append +foo to the current version number (foo can be any string of lowercase letters; and be careful if you use dch -i, it will increment the last number, so you need to revert it to the current one) and to use the correct release name (artful here). Finally, run dpkg-source --commit.

You can then run the debuild command, and if everything goes well (errors about debsign can be ignored) you should have some .debs in the parent directory, which you can install as usual (there is no need to install all of them, just the ones you have now; use dpkg -l | grep bash to find out).

Note that the version number of the new package is set so that you will automatically get any future update to bash; if the update does not fix the problem, you have to repeat the above process.

(This answer was first posted on this duplicate question.)

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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