Non-recursively replace all uppercase letters in files within current directory with lowercase letters - without looping Let's say that I have a directory that looks like this:

dir
    | File1.txt
    | fILE2.md
    | file3.tex


When I execute my bash script from within the dir directory, I want to receive files with names "file1.txt", "file2.md" and "file3.tex".

I have written this script:

ls | xargs -n1 -I {} sh -c 'fst={}; snd=`echo $fst | tr [:upper:] [:lower:]`; mv $fst $snd'


It works but is complex (uses variables). Is there a nicer way to perform it by piping commands? I don't want to use loops.
The design constraint of "repeat (some action) without loops" is nonsensical.  

Any solution that is not "type every rename command yourself" involves a loop.  The loop may be hidden inside xargs and awk or rename; it's still there.

Anyway, assuming the files are like you say (well-formed, no embedded whitespace, all printable characters), you can have awk generate a shell script and feed that to a shell:

\ls | awk '/[A-Z]/ {print "mv",$1,tolower($1)}' | sh


If you need to deal with spaces and special characters, add quotes and use $0 (whole line) instead of $1 (first field):

\ls | awk '/[A-Z]/ {printf "mv '\''%s'\'\ \''%s'\''\n",$0,tolower($0)}'


If the filenames contain ' then this will fail and you need to work that out.  Your code has the same problem.  I won't get into the solution here because it involves a zillion backslashes and is the wrong way to solve this problem.

The right way to solve this problem is to use a tool built for the task (rename) or a shell loop.  And adding -i is a good idea, in case the new filename already exists.  This will work with any filename:

for f in *[A-Z]* ; do mv -i -- "$f" "${f,,}"; done