Python for Network Engineers

Using Linux Xargs

by: George El., October 2018, Reading time: 4 minutes

xargs is very useful utility because it takes standard input and passes it to the next function. In most cases it can replace a for loop

lets say I wanna zip each txt file1-9 individually

$ls -1 *.txt |  xargs -n1 gzip 
file1.txt.gz
file2.txt.gz
file3.txt.gz
file4.txt.gz
file5.txt.gz
file6.txt.gz
file7.txt.gz
file8.txt.gz
file9.txt.gz

to unzip

$ls -1 *.gz |  xargs -n1 gzip -d
ls -1
file1.txt
file2.txt
file3.txt
file4.txt
file5.txt
file6.txt
file7.txt
file8.txt
file9.txt

to be verbose use -t

$ ls -1 | xargs -n1 -t gzip
gzip file1.txt
gzip file2.txt
gzip file3.txt
gzip file4.txt
gzip file5.txt
gzip file6.txt
gzip file7.txt
gzip file8.txt
gzip file9.txt

lets unzip the files again

$ ls -1 | xargs -n1 gzip -d
$ ls -1
file10.txt
file1.txt
file2.txt
file3.txt
file4.txt
file5.txt
file6.txt
file7.txt
file8.txt
file9.txt

lets rename the files by adding zeros at the end

ls -1 | pcregrep --om-separator " " -o0 -o1 -o2 "([a-z]+)([0-9]+)\.txt" | xargs printf "%s %s%03d.txt\n" | xargs -n2 mv
$ ls -1
file000.txt
file001.txt
file002.txt
file003.txt
file004.txt
file005.txt
file006.txt
file007.txt
file008.txt
file010.txt

lets add the numbers in the beginning

$ ls -1
file10.txt
file1.txt
file2.txt
file3.txt
file4.txt
file5.txt
file6.txt
file7.txt
file8.txt
file9.txt
$ ls -1 | pcregrep --om-separator " " -o0 -o2 -o1 "([a-z]+)([0-9]+)\.txt" | xargs -n3 -t printf "%s %03d%s.txt\n"
printf %s %03d%s.txt\n file10.txt 10 file
file10.txt 010file.txt
printf %s %03d%s.txt\n file1.txt 1 file
file1.txt 001file.txt
printf %s %03d%s.txt\n file2.txt 2 file
file2.txt 002file.txt
printf %s %03d%s.txt\n file3.txt 3 file
file3.txt 003file.txt
printf %s %03d%s.txt\n file4.txt 4 file
file4.txt 004file.txt
printf %s %03d%s.txt\n file5.txt 5 file
file5.txt 005file.txt
printf %s %03d%s.txt\n file6.txt 6 file
file6.txt 006file.txt
printf %s %03d%s.txt\n file7.txt 7 file
file7.txt 007file.txt
printf %s %03d%s.txt\n file8.txt 8 file
file8.txt 008file.txt
printf %s %03d%s.txt\n file9.txt 9 file
file9.txt 009file.txt

Now that my files have correct names I need to pipe it one more for the mv command

$ ls -1 | pcregrep --om-separator " " -o0 -o2 -o1 "([a-z]+)([0-9]+)\.txt" | xargs -n3 printf "%s %03d%s.txt\n" | xargs -n2 -t mv
$ ls -1
mv file10.txt 010file.txt
mv file1.txt 001file.txt
mv file2.txt 002file.txt
mv file3.txt 003file.txt
mv file4.txt 004file.txt
mv file5.txt 005file.txt
mv file6.txt 006file.txt
mv file7.txt 007file.txt
mv file8.txt 008file.txt
mv file9.txt 009file.txt
$ ls -1 
001file.txt
002file.txt
003file.txt
004file.txt
005file.txt
006file.txt
007file.txt
008file.txt
009file.txt
010file.txt

if you want to execute multiple commands you have to run commands in another shell and use the -I argument

ls -1 | xargs -n1 -t -Isome_file bash -c '{ echo "some_file"; tar cvf "some_file.tar" "some_file"; }'

find all file* in /home/user, echo and delete them
find /home/user -type f -name "file*" | xargs -n1 -I{} sh -c 'echo {}; rm {}'

if you want to reorder args you have to go through an intermediate shell

ls -1 | sed -r 's/[0-9]+/ & /'  | xargs -n3 bash -c '{ printf "%02d%s%s\n" "$1" "$0" "$2"; }'
$ ls -1
file10.txt
file11.txt
file12.txt
file1.txt
file2.txt
file3.txt
file4.txt
file5.txt
file6.txt
file7.txt
file8.txt
file9.txt

I will rename the files now using the xargs utility and sed

$ ls -1 | sed -r 's/([a-z]+)([0-9]+)(\.txt)/\2 \1 \3/' | xargs -n3 printf "%02d-%s%s\n"
10-file.txt
11-file.txt
12-file.txt
01-file.txt
02-file.txt
03-file.txt
04-file.txt
05-file.txt
06-file.txt
07-file.txt
08-file.txt
09-file.txt
$ ls -1 | sed -r 's/([a-z]+)([0-9]+)(\.txt)/& \2 \1 \3/'
file10.txt 10 file .txt
file11.txt 11 file .txt
file12.txt 12 file .txt
file1.txt 1 file .txt
file2.txt 2 file .txt
file3.txt 3 file .txt
file4.txt 4 file .txt
file5.txt 5 file .txt
file6.txt 6 file .txt
file7.txt 7 file .txt
file8.txt 8 file .txt
file9.txt 9 file .txt
$ ls -1 | sed -r 's/([a-z]+)([0-9]+)(\.txt)/& \2 \1 \3/' | xargs -n4 printf "%s %02d-%s%s\n"
file10.txt 10-file.txt
file11.txt 11-file.txt
file12.txt 12-file.txt
file1.txt 01-file.txt
file2.txt 02-file.txt
file3.txt 03-file.txt
file4.txt 04-file.txt
file5.txt 05-file.txt
file6.txt 06-file.txt
file7.txt 07-file.txt
file8.txt 08-file.txt
file9.txt 09-file.txt
$ ls -1 | sed -r 's/([a-z]+)([0-9]+)(\.txt)/& \2 \1 \3/' | xargs -n4 printf "%s %02d-%s%s\n" | xargs -n2 -t mv
mv file10.txt 10-file.txt
mv file11.txt 11-file.txt
mv file12.txt 12-file.txt
mv file1.txt 01-file.txt
mv file2.txt 02-file.txt
mv file3.txt 03-file.txt
mv file4.txt 04-file.txt
mv file5.txt 05-file.txt
mv file6.txt 06-file.txt
mv file7.txt 07-file.txt
mv file8.txt 08-file.txt
mv file9.txt 09-file.txt
$ ls -1
01-file.txt
02-file.txt
03-file.txt
04-file.txt
05-file.txt
06-file.txt
07-file.txt
08-file.txt
09-file.txt
10-file.txt
11-file.txt
12-file.txt
comments powered by Disqus