1

I get to understand that this code is for bash shell

for f in $file.docked.[0-9][0-9][0-9]
do
  mv $f $f.pdb
done

And this code is for tcsh shell

foreach f ( file.docked.[0-9][0-9][0-9] )
  mv $f $f.pdb
end

This I understood after reading from references. As a learner, I had the perception that both the codes will work in bash. Is there a way to find out which shell a particular code will work without full knowledge about the different shell. Extending is there a way to make code work on all the shell independent of the type of shell of Linux it was written on?

7
  • 5
    Can't resist mentioning unix.stackexchange.com/a/71137/117549
    – Jeff Schaller
    Commented May 31, 2020 at 16:30
  • 2
    Ordinarily, one knows what language one writes code in. You may treat each shell as a separate language. If you write bash code, don't expect to be able to run it with sh or tcsh or zsh. It may work, just like running some Python statements with a Perl interpreter may possibly work, but it would be based on luck, mostly. Usually, the correct interpreter is indicated by the #! line at the top of the script.
    – Kusalananda
    Commented May 31, 2020 at 16:53
  • @JeffSchaller I really wish you had not mentioned that page. It gives me a headache just looking at it. :)
    – doneal24
    Commented May 31, 2020 at 17:15
  • 2
    When writing the code specify the interpreter at the top (in the first line): e.g. #!/bin/bash Commented May 31, 2020 at 21:44
  • 1
    I sympathize to an extent, but the mainstream English usage is that "code" is an uncountable noun in contexts such as these,
    – JdeBP
    Commented Jun 1, 2020 at 2:45

1 Answer 1

6
for f in $file.docked.[0-9][0-9][0-9]
do
mv $f $f.pdb
done

Is syntactically valid code in csh, tcsh and all shells of the Bourne family (ash, bash, zsh, ksh, zsh, mksh, yash...) but it's in zsh that it's most likely to be doing something useful.

If the intent of that code is to add a .pdb suffix to the names of files in the current directory that start with the contents of the $file shell variable and end in .docked. followed by 3 ASCII decimal digits, in bash, you'd need:

shopt -s failglob
for f in "$file".docked.[0123456789][0123456789][0123456789]
do
mv -- "$f" "$f.pdb"
done

(the -- is needed regardless of the shell) as in bash

  • like in the Korn shell, you need to quote parameter expansions as otherwise they undergo split+glob
  • [0-9] generally matches a lot more characters than just 0123456789, the list of which varies with the locale and the system. You need [0123456789] in bash to match on 0123456789 only (and no, the globasciiranges option of recent versions doesn't help).
  • globs are left unexpanded when they don't match, so you'd get one pass in the loop with a $f containing contents-of-file-variable.docked.[0-9][0-9][0-9] if there was no matching file. failglob (to get a behaviour similar to that of csh or zsh) or nullglob (an option copied from zsh) address that.
foreach f ( file.docked.[0-9][0-9][0-9] )
  mv $f $f.pdb
end

Does look like csh syntax, but again that's rather zsh syntax. In (t)csh that should rather be:

foreach f ( file.docked.[0-9][0-9][0-9] )
  mv -- $f:q $f:q.pdb
end

(though in that particular case, the :qs are not strictly necessary as contrary to the other sample, the file names are guaranteed not to contain SPC, TAB, LF or wildcard characters).

Writing code that is valid and does the same thing in completely different languages is very tricky. It's generally called polyglot coding. The Code Golf stackexchange sister site has a section for that. But that's not the kind of thing you would want to do normally.

See this example on this site as an example of the kind of length you need to go to to achieve it.

4
  • Can you explain the shopt -s failglob a bit more deep. I read the documentation in man bash and found the following for failglob -- If set, patterns which fail to match filenames during pathname expansion result in an expansion error. So by means of setting it, are you making it to show expansion error? Commented Jun 1, 2020 at 8:12
  • Also what does the -- in mv stand for ? Commented Jun 1, 2020 at 8:13
  • 1
    @PraveenKumar-M With failglob you get an error instead of one pass in the loop with a bogus filename when the glob fails to match any file. About --, see What does "--" (double-dash) mean? Commented Jun 1, 2020 at 8:26
  • This fixes it. Done. Commented Jun 1, 2020 at 9:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .