0

I have a bash script where I loop over all files in a directory using

for x in "$path/"{.,}*; do
    do some stuff here  
done

This does loop over all the files and directories (this is what I want), but it also gives me the file .* which does not exist. I am using a terminal emulator on android, so it could be an error there. I am looking for a shell solution as I don't have most of the "normal Linux" commands such as sed.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Use the `{}` button in the editor, or add four-space indents before each line, for multi-line code blocks. – Charles Duffy May 26 '17 at 00:19
  • That said, your goal is just to make sure that hidden files are included in the glob expression, right? Easier just to tell the shell that that's what you want. – Charles Duffy May 26 '17 at 00:22
  • (That said, `.*` will always have matches on standard Linux filesystems -- even if those matches are only the directories `.` and `..` -- so I'm curious about your platform where you're getting a contrary result) – Charles Duffy May 26 '17 at 00:25
  • ...that said -- is your shell **really** bash, or is it something like busybox ash (which supports only real POSIX sh syntax, without bash extensions)? Per https://stackoverflow.com/questions/11950131/android-adb-shell-ash-or-ksh, it looks like it's probably either ash or mksh, **not** bash. If that's the case, you should probably adjust the question's tagging. – Charles Duffy May 26 '17 at 00:27
  • as for the {} button or indentations, thanks, I only had a textbox no editor buttons, I'll try to remember the four indentations. Indeed I also want hidden files, platform is a terminal emulator app, whith a subset of posix bash (if that is the correct term) I had to write my own basename for example – pietervanderstar May 26 '17 at 07:43
  • "POSIX sh" is the standard specifying baseline shell functionality. bash is a *specific implementation* of a large superset of that standard, written by Chet Ramey as part of the GNU project. (basename, btw, is *not* part of bash itself, but is a [POSIX-specified utility](http://pubs.opengroup.org/onlinepubs/009696699/utilities/basename.html) that an OS that wants to claim POSIX-compliance should provide; that said, I also consider it pretty useless -- `result=${var##*/}` is far faster to execute than `result=$(basename "$var")`, after all, and uses only builtin functionality. – Charles Duffy May 26 '17 at 14:57

1 Answers1

0

If Your Shell Is Really Bash (as the question originally stated)

Running the following command:

shopt -s nullglob

will disable the default behavior of leaving globs with no matches unexpanded. Note that this can have surprising side effects: With nullglob set, ls -l *.NotFilenamesHaveThisSuffix will be exactly the same as ls -l.


That said, you can do even better:

shopt -s dotglob
for x in "$path/"*; do
    printf 'Processing file: %q\n' "$x"  
done

will, on account of setting dotglob, find all hidden files without needing the {.,} idiom at all, and will also have the benefit of consistently ignoring . and ...


If Your Shell Is ash Or mksh

It's actually quite usual to find bash on an Android device. If you have a baseline POSIX shell, the following will be more robust.

for x in "$path"/* "$path"/.*; do
  [ -e "$x" ] || continue                      # skip files that don't exist
  basename=${x##*/}                            # find filename w/o path
  case $basename in "."|"..") continue ;; esac # skip "." and ".."

  echo "Processing $x" >&2
  : ...put your logic here...
done
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • I already used the -e solution, but I was hoping there would be a solution that would not include .* in the list. But I can work with this behaviour. I actually don't get the . and .. Could you explain why the .* might end up in the list? – pietervanderstar May 26 '17 at 11:03
  • It would end up in the list if there are no files that start with `.`, and your shell doesn't include `.` or `..` in output unconditionally (which would mean that shell *definitely* isn't bash, which will include those as results when globbing `.*`). – Charles Duffy May 26 '17 at 14:39
  • This is because the shell's default behavior when a glob doesn't match is leaving the non-matching pattern in place. That way, `ls -l *.txt` gives you `*.txt: no such file exists` instead of behaving exactly like `ls -l` with no arguments and showing a list of all files in the current directory even though none of them match the glob. – Charles Duffy May 26 '17 at 14:40
  • Keep in mind that curly brace expansion isn't globbing -- it happens whether or not such files exist. Thus, `{.,}*` is exactly the same as passing `.*` and `*` separately, and each of those is evaluated as an independent glob expression (and left in the argument list if it doesn't match). – Charles Duffy May 26 '17 at 14:43
  • ...anyhow, if you don't want `.*` in the list even when it doesn't expand to anything, the solution is to use a shell (like bash!) with `nullglob` support. – Charles Duffy May 26 '17 at 14:52
  • Thanks it is clear now, so thanks for updating the title – pietervanderstar May 26 '17 at 18:55