4

i wonder if u could help me with fixing bash script which should unhide all hiden files in dir. Where is the problem?

param='.'
for file in $param*; do
mv $file $(echo $file | sed 's/^.\(.*\)/\1/')
done
exit
anubhava
  • 761,203
  • 64
  • 569
  • 643
Liudis
  • 43
  • 1
  • 5

4 Answers4

7

This for loop should work:

export GLOBIGNORE=".:.."
for file in .*; do
   mv -n "$file" "${file#.}"
   # mv -n "$file" "${file:1}"
done

PS: Better to backup your files before doing a mass mv/rename

anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    Won't this try to rename `.` and `..` as well ? – damienfrancois Nov 18 '13 at 22:18
  • anubhava could u explain ur that mv line? It is working. Thanks in advance! – Liudis Nov 18 '13 at 22:23
  • 1
    You could also have written `mv "$file" "${file:1}"` – damienfrancois Nov 18 '13 at 22:24
  • 1
    See, amongst other places, [What does the curly brace syntax mean in `bash`?](http://stackoverflow.com/questions/9558986/what-does-the-curly-brace-syntax-mean-in-bash/9559024#9559024) – Jonathan Leffler Nov 18 '13 at 22:24
  • 3
    You could also `export GLOBIGNORE=".:.."` in your script, then using `.*` will skip those. – mpontillo Nov 18 '13 at 22:27
  • @user2988575: `"${file#.}"` removes first dot from the input string. Yes you can also use `"${file:1}"` which means substring from 1st character onwards (discarding 0th position dot) – anubhava Nov 18 '13 at 22:27
  • 1
    Might also want to `test -e "${file#.}"` before moving another file on top of an existing one. ;-) – mpontillo Nov 18 '13 at 22:33
  • @Mike: Thanks I made it `mv -n` to skip overwriting an existing file. – anubhava Nov 18 '13 at 22:35
  • 1
    @Mike: While `export GLOBIGNORE=".:.."` is arguably a reasonable global default, it should be noted that you're changing *global* state with it - which may have unintended effects on subsequent commands. To safely localize the effect of setting `GLOBIGNORE`, drop the `export` and enclose the entire block (assigning to `GLOBIGNORE`, plus the `for` loop) in parentheses. – mklement0 Nov 19 '13 at 00:09
  • @mklement0 what was I thinking. `.[^.] .??*`. – jthill Nov 19 '13 at 00:17
  • @jthill: Your thinking was promising - provide a self-contained pattern expression that doesn't rely on global state (`GLOBIGNORE`) - it *almost* works, if it weren't for the duplicates. (To correct my earlier comment: unfortunately, you don't get a strict union in a set-theory sense, but a *multiset*.) – mklement0 Nov 19 '13 at 00:29
  • 1
    @mklement0 This one gets dups? I can't see it, can you provide an example? Btw, none of the examples here work reliably without `shopt -s nullglob`, which I think also isn't a default. With `GLOBIGNORE` and no dotfiles you get `.*` – jthill Nov 19 '13 at 00:39
  • @mklement0 ah, no, I was referring to the corrected pair w/o the brainfart, `.[^.] .??*`. Either way, I'm pretty sure we've covered this exhaustively :-) – jthill Nov 19 '13 at 04:07
  • Good point re `shopt -s nullglob`. Your corrected pattern - `.[^.] .??*` - indeed works correctly (but also needs `shopt -s nullglob`). See my answer for a robust solution. – mklement0 Nov 21 '13 at 03:39
1

@anubhava's answer works, but here's an amended, generalized solution for processing hidden files/folders, which:

  • correctly deals with edge cases (the absence of hidden files/folders).
  • neither depends on nor alters global state (configuration).

    ( # Execute in subshell to localize configuration changes below.
    GLOBIGNORE=".:.."   # Do not match '.' and '..'.
    shopt -s nullglob   # Expand globbing pattern to empty string, if no matches.
    for f in .*; do     # Enumerate all hidden files/folders, if any.
      # Process "$f" here; e.g.: mv -n "$f" "${f:1}"
    done
    )
    

If you want to avoid a subshell, you can use the following approach, which explicitly rules out . and .. and also an unexpanded pattern in case there are no matches (if GLOBIGNORE happens to contain .:..):

    for f in .*; do
     if [[ $f != '.' && $f != '..'  && -e $f ]]; then
        # Process "$f" here; e.g.: mv -n "$f" "${f:1}"
     fi
    done

Tip of the hat to @jthill, @anubhava, @Mike.

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

I wouldn't mass-rename them like that myself, I'd add visible symbolic links to them:

while read f; do
        ln -s "$f" "visible-${f#./}"
done <<EOD
$(find -mindepth 1 -maxdepth 1 -name '.*')
EOD
jthill
  • 55,082
  • 5
  • 77
  • 137
0

This will only unhide all hidden files, keep away from your home directory!!!

ls -1Ap |grep "^\." |grep -v "/" |while read F; do mv $F ${F:1}; done

This will unhide all hidden files and dirs, again: keep away from your home directory!!!

ls -1A |grep "^\." |while read F; do mv $F ${F:1}; done

Best you can do to test these kind of dangerous games is to make yourself an extra account on your machine...If you screw up your own account there will be "tears unlimited(tm)"

If you want to test it first (which is a VERY sensible thing to do):

ls -1A |grep "^\." |while read F; do echo "mv $F ${F:1}"; done
thom
  • 2,294
  • 12
  • 9