2

I got access to only Busybox 1.31.1

I originally wanted to remove the current working directory of my output (the single dot).

Example:

/prueba$ ls
uno dos tres

When I:

$ busybox find .
.
./uno
./dos
./tres

That's easily done with either:

busybox find . -not -path .
busybox find . -mindepth 1

Now, what I tried before is:

busybox find . -exec sh -c ' readlink -f "$1" | tail -n +2 ' sh {} \;

Which prints nothing. If verbose output is activated:

==> standard input <==
==> standard input <==
==> standard input <==
==> standard input <==
==> standard input <==

Completely different output if the line address is one:

busybox find . -exec sh -c ' readlink -f "$1" | tail -n +1 ' sh {} \;
==> standard input <==
/tmp/prueba
==> standard input <==
/tmp/prueba/tres
==> standard input <==
/tmp/prueba/dos
==> standard input <==
/tmp/prueba/uno

What's going on?

abacox
  • 143
  • 8
  • I suppose you mean `-mindepth 1`, not `-maxdepth 1`, since the `.` given on the command line is at depth 0. But is there a particular reason to use `tail` and not the two ways you already have for removing `.` from the output of `find`? – ilkkachu Sep 09 '21 at 14:14
  • @ilkkachu Hello. Yes, I'll will edit my post. No, there is no particular reason to use tail I was using it due to ignorance, I tought that was the way to go, but after knowing that find can do it by itself I was just curious why I wasn't getting the output I wanted. – abacox Sep 12 '21 at 02:15
  • yep, just wondering. Namely, `find . -not -path . -exec ...` should work too. – ilkkachu Sep 12 '21 at 10:35
  • I was told `-not` is non-standard, better to use `!` which is standard complaint. Any literature work you can recommend to know the "right" way? – abacox Sep 13 '21 at 00:10
  • 1
    right, `!` is the standard one. Though just based on the man pages, the GNU, FreeBSD, OpenBSD and Busybox versions support `-not` too. (Plus `-and` and `-or` which are similarly nonstandard variants of `-a` and `-o`.) In this case, the [GNU manpage](https://man7.org/linux/man-pages/man1/find.1.html) even mentions those are not POSIX compliant. The [specification is online](https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/find.html) too, but as you might guess with a standard, it's not always the most fluent read. – ilkkachu Sep 13 '21 at 07:44

1 Answers1

3

The

-exec some command with parms {} \;

invokes the command once for each file. In your case the readlink outputs one line of output, and then your tail -n +2 strips off the first line, leaving you with nothing. If you use tail -n +1 this is just a verbose way of saying cat, to copy the input to output.

If you rewrite it so the tail -n +2 is outside the implicit loop like this

busybox find . -exec sh -c ' readlink -f "$1" ' sh {} \; | tail -n +2

you will get your expected result.

You can make the command more efficient by batching the command execution.

busybox find . -exec readlink -f -- {} + | tail -n +2

This requires the command you want to run taking multiple files. The + rather than the \; makes find run the command many fewer times as it runs the command only when it has a full buffer of filenames rather than once per file. Obviously I have also removed the unneeded sh as well.

icarus
  • 17,420
  • 1
  • 37
  • 54
  • Thank you very much, I'm amazed on how quickly a clear and well done explanation can be provided within minutes. Internet is awesome, you guys are awesome! About the unneeded sh . I did because I tend to work with multiple files with non ASCII names and with spaces as well. So I followed this advise, just to be on the safe side: https://unix.stackexchange.com/a/156010 – abacox Sep 08 '21 at 05:43
  • 1
    The point about spaces and other 'interesting' characters in names is that they are a problem for the shell. Remove the extra shell and the issue with spaces goes away. I added an extra `--` to the answer so filenames like `-m` don't cause problems. – icarus Sep 09 '21 at 14:08
  • What `--` does? Is it for `find` or for `readlink`? – abacox Sep 12 '21 at 02:58
  • 1
    `--` is a standard convention to indicate the end of options. This allows you to distinguish between a file called `-i` and an option `-i`. In this case it is for readlink. – icarus Sep 12 '21 at 07:10
  • 1
    Strictly speaking, while it's good practice to use `--` and never harms, here it's not strictly necessary as all arguments will start with `./` – Stéphane Chazelas Sep 12 '21 at 07:40
  • 1
    @StéphaneChazelas Totally agree. The problem only arises if `.` is replaced with a list of files. The most likely way that an unsuspecting person would generate such a list is with filename expansion. I haven't seen the advice recently but at one time there was a suggestion to have a file called `-i` so if you typed `rm *` and the filename came first or your version of argument parsing sorted `options` to the front you would get some warning that you were about to delete more than you expected. – icarus Sep 12 '21 at 14:56
  • 2
    @icarus, yes, there's (or at least was) such a `-i` file in the source tarball of `bash` for that reason. Note that `--` is necessary with `-execdir` with some implementations of `find`. – Stéphane Chazelas Sep 12 '21 at 17:07