3

I would expect under bash for the following:

 ls *.py | xargs -I{} echo $(echo {} | sed 's/\.py/_2\.py/g')

to list all .py files contained in the directory but with _2 annexed after the file name and before the .py extension.

Yet this is not what happens. It simply lists the .py files in the directory without any change.

In short:

$ ls
A.py  B.py

$ ls *.py | xargs -I{} echo $(echo {} | sed 's/\.py/_2\.py/g')
A.py
B.py

while the output I expected would've been:

A_2.py
B_2.py

What happens here and how to get the expected output?

Amaterasu
  • 293
  • Why not ls *.py | xargs -I{} echo {} | sed 's/\.py/_2\.py/g'? – Philippos Aug 30 '19 at 08:06
  • 1
    @Philippos well, for this even ls *.py | sed 's/\.py/_2\.py/g' works... the reason is that this is testing, I want to replace the echo after the -I{} with a command like cp, mv, ... – Amaterasu Aug 30 '19 at 08:09
  • 1
    In that case, don't parse the output of ls and use find ... -exec ... instead. See also https://unix.stackexchange.com/q/128985/364705 – markgraf Aug 30 '19 at 08:11
  • 1
    @Amaterasu Depends on what you do in the exec :-) find . -type f -name '*.py' -exec sh -c 'a={}; mv "$a" "${a%.py}_2.py"' \; – markgraf Aug 30 '19 at 08:38
  • @markgraf yeah, well that works and you can have a "preview" what files will be renamed. find -name "*.py" -exec cp -n {} {}_2 \; -exec rename .py_2 _2.py {} \; otoh is less baroque but it can't be tested ... and is it really safe? – Amaterasu Aug 30 '19 at 09:00

1 Answers1

3

This happens because the command in subshell i.e.

echo {} | sed 's/\.py/_2\.py/g'

executes before echo, so after this command the command will be:

xargs -I{} echo {}

which will simply echo all the file_names.

You can use find command:

find directory_name -name '*.py' \
-exec rename 's/.py/_2.py/' {} +

It will rename all the files in just one command.

To find files in current directory only not subdirectories, use maxdepth 1 option i.e.:

find directory_name -maxdepth 1 -name '*.py' \
-exec rename 's/.py/_2.py/' {} +
Prvt_Yadav
  • 5,882
  • Can you also copy with that command rename in one pass? – Amaterasu Aug 30 '19 at 08:32
  • Note that the user is only accessing .py files in the current directory. This makes the use of find unnecessary. – Kusalananda Aug 30 '19 at 08:33
  • @Amaterasu this command will be like rename 's/.py/_2.py/' file1.py file2.py ...., see https://stackoverflow.com/questions/29360925/whats-the-difference-between-and-at-the-end-of-a-find-command – Prvt_Yadav Aug 30 '19 at 08:53
  • @Amaterasu no, but you can have more than one -exec in a single find command. e.g. -exec cp ... \; first, followed by -exec rename ... +. By default, the second -exec (rename) will only be run for files where the first (cp) returned true. – cas Aug 30 '19 at 10:05