39

I have an emergency, Linux and Bash beginner here and messed up trying to write a script to rename some files. The loop accidentally went up the path (ran the script in a folder in Desktop) and renamed /bin to /D_bin (D_ was the prefix I added) so now the system can't use /bin contents, so no bash, no mv to rename, no sudo... The files in /D_bin are ok, not renamed, and can copy-paste them but can't create folder /bin again without bash. The system looks stable but very few things work and have no access to files in Desktop.

The other folders of / like /lib /sbin /etc seem to be ok too, and the graphical desktop is still there. I'm afraid of restarting because I don't know if it will be able to boot.

Is there a shell in root or a way to rename /D_bin back to /bin? Need help please, very important work compromised

My suicidal script :$ :

#!/bin/bash
files=~/Desktop/folder_1/*

for j in $files
do
    cd $j
    for i in 10n*  #file names starting by 10n
    do
       find * -maxdepth 0 ! -path . -exec mv {} D_{} \;
    done
    cd ..
done

:( Thanks!!!!

derHugo
  • 3,306
  • 5
  • 30
  • 49
  • 7
    You could try using a VM to try and learn this kind of things, so you'd never risk much. – M. Becerra Apr 02 '17 at 13:00
  • 7
    Now to fix the issue, you could make a bootable USB with Ubuntu as if you wanted to install the OS and press *Try Ubuntu*, from there you could open a terminal and rename the folder. – M. Becerra Apr 02 '17 at 13:02
  • Thank you very much. About the VM I use some packages that don't work well or allow virtualization. Have to be more careful next time indeed, just kind of adapted this script a bit recklessly but lesson learned. – Carlos D. Zapata Apr 02 '17 at 14:01
  • 2
    Possible duplicate of [Revert moving root directory recursively](http://askubuntu.com/questions/332019/revert-moving-root-directory-recursively) – muru Apr 02 '17 at 17:01
  • 32
    `/D_bin/mv -T /D_bin /bin` and don't run your scripts as root next time. – Jason C Apr 02 '17 at 20:39
  • 5
    Btw when making scripts like this I usually do a dry run first by having the script echo potentially destructive commands instead of running them and verifying that its actions will be sane. Also: regular backups. – Jason C Apr 02 '17 at 20:42
  • 1
    Now kids, this is why you don't just run stuff as sudo. Btw, why does your user seem to have root perms on /? – djsmiley2kStaysInside Apr 03 '17 at 14:10
  • Looks like a bad case of missing `-e` flag in bash. – Kos Apr 04 '17 at 07:53

2 Answers2

89

There are several ways to fix this issue.

If you have access to a shell (any open terminal), run:

sudo /D_bin/mv -T /D_bin /bin

sudo is in /usr/bin so there is no need to run it with absolute path.

The other thing you can do is, adding the /D_bin to your PATH environment variable, like this:

export PATH=$PATH:/D_bin

If you don't have access to any shell:

  1. reboot the system
  2. when grub appears press e to edit the grub
  3. at the end of the line which starts with linux, add:

    init=/D_bin/bash
    
  4. press CTRL+x

Now you will be dropped into a bash shell, you should remount file system as read and writable.

/D_bin/mount -o remount,rw /

And move the D_bin directory to bin:

/D_bin/mv -T /D_bin /bin

Then reboot the system.

It should work, but if nothing worked for you, you still can boot the system with a live ubuntu disk/usb and fix the issue.

Ravexina
  • 54,268
  • 25
  • 157
  • 179
  • 3
    The first one solved it. Thanks a lot, really saved my day. Out of curiosity, by watching the script why the renaming reached /bin? All the folders in Desktop got the '_D' but not any other at home or at root except for bin. – Carlos D. Zapata Apr 02 '17 at 13:50
  • 9
    @CarlosD.Zapata: if you need to change directory in a loop in a script, it is often a good idea to run the code in a sub-she'll. Add an open parenthesis before the `cd "$j"` (the name should be in double quotes), and replace the mischief-making `cd ..` with the matching close parenthesis. Also, why were you running as root. You shouldn't be able to do that much damage. – Jonathan Leffler Apr 02 '17 at 14:16
  • 3
    @CarlosD.Zapata: after your `cd ..` put a `pwd`, remove your `find` command from script, then run it as a normal user. you'll see the script goes into `/`, because you do a cd $j which I guess are files not directories. so in each loop you go one step back and finally you are in `/`. – Ravexina Apr 02 '17 at 14:24
  • @Ravexina: I did the test but I don't see it reaches /. It reports pwd for the folders at the same level of the script location, and reports the files there not being directories. But doesn't go up now. With the damaging run it went to some of the same level folders, entered, added the prefix to each file as many times as the number of files in each of those folders, then went up and changed folder names but didn't access other branches and then reached Home but there it didn't change folder names. But /bin was changed somehow. Anyway, not to waste time there, gotta be more careful next time. – Carlos D. Zapata Apr 02 '17 at 15:36
  • 1
    @CarlosD.Zapata Keep in mind that it might have "stopped" on `/bin` because it was working on folders inside `/bin`. I'd check those (though not as root!) – wizzwizz4 Apr 02 '17 at 17:22
  • 17
    It probably stopped on /bin because /bin was the first folder in / that it happened to rename (it's alphabetically first), and after that, it couldn't run `mv` any more. – user253751 Apr 03 '17 at 01:17
8

To fix this problem if you have no running terminal open, I would first try to find a “shell substitute” that you can use instead of bash. Python is in /usr/bin, so that should still work.

Python 2.7.6 (default, Oct 26 2016, 20:30:19) 
[GCC 4.8.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> subprocess.call(["sudo", "/D_bin/mv", "-T", "/D_bin", "/bin"])

If that doesn't work, I'd just straight boot from live CD / USB and fix everything from a known-sane running environment.

As a general advice, I'd second Jonathan Leffler in the comments: never use cd .. in scripts, it can easily lead to such problems. Better only cd into the $j directory within a subshell, this way you don't have to worry about getting back.

#!/bin/bash
files=~/Desktop/folder_1/*

for j in $files
do
  (
    cd "$j"
    for i in 10n*  #file names starting by 10n
    do
       find * -maxdepth 0 ! -path . -exec mv {} D_{} \;
    done
  )
done

Also, of course, don't run stuff as root unless absolutely necessary.

leftaroundabout
  • 846
  • 7
  • 19
  • Is it possible to run an interactive shell like python without having access to any other shell/terminal? I think the workaround should be creating a script which contains command alongside the password to run it as root. GUI will do the rest I guess. – Ravexina Apr 03 '17 at 13:31
  • @Ravexina: [not everything can need a shell](https://en.wikipedia.org/wiki/Turtles_all_the_way_down). Pretty sure to run the `python` process you just need a terminal application, and to run `os.system("sudo ...")` you just need a *nix kernel. Maybe I'll try it out in a VM later... – leftaroundabout Apr 03 '17 at 14:02
  • Additionally, when `cd`ing in scripts, it's usually better to `cd -` to go back to where you were, rather than assuming you cd'd one directory down. If you change the initial `cd`, then the `cd ..` won't get you back to where you were, but `cd -` will. – 000 Apr 03 '17 at 16:50
  • @JoeFrambach like `cd ..` I would _not_ use `cd -` in scripts, only at the command-line. `cd -` is perhaps less of a trouble-guarantee than `cd ..`, but I still wouldn't consider it _safe_ – if somebody adds further directory changes in the middle, it'll take you somewhere unintended. Whereas subshells give you a _clearly delimited scope_ for where the directory changes, and to which point you go back. – leftaroundabout Apr 03 '17 at 19:04
  • @Ravexina I just tried it: Python can indeed be launched. Its `os.system` does _not_ work without `sh` present, but `subprocess.call` works. – leftaroundabout Apr 03 '17 at 22:29