What does this bash command do? - bash

What does this command do? Can it be shortened without losing functionality?
echo "abcabcabc" | sed "s/aBc/xyZ/gi;s/Z/a/;s/c/CCC/g" | xargs ls -ld

You would know what the command does if you entered it on a Mac OS terminal. It doesn't do anything but producing an error because the i in the sed command seems to be wrong or a typing error. However
echo "abcabcabc" | sed "s/aBc/xyZ/g;s/Z/a/;s/c/CCC/g" | xargs ls -ld
outputs the string abcabcabc which is used as input for the sed command which replaces aBc with xyZ, Z with a and c with CCC. This results in the string abCCCabCCCabCCC which is again input for the ls -ln command. If you had a file with the name abCCCabCCCabCCC in the current directory it would be found and it's details would be shown to you, otherwise the output is
ls: abCCCabCCCabCCC: No such file or directory
If it could be shortened depends on what you really want to achieve.
echo "abcabcabc" | sed "s/c/CCC/g" | xargs ls -ld
would have the same result in this case.

Related

How to understand xargs

Saying that I have two files t1 and t2, they have the same content: abc.
Now I want to delete all files, who contains the string abc.
So I tried to execute the command: grep -rl abc . | rm but it doesn't work.
Then I add xargs: grep -rl abc . | xargs rm and it works.
I can't understand clearly what xargs did.
grep puts the output as stdout. But rm cannot process data from stdin (the pipe links both).
You want instead, that the output of grep is put as argument of rm. So xargs command "convert" stdin into arguments of xargs first argument, and it call the command (the first argument).
As alternative, you could do
rm `grep -rl abc .`
or
rm $(grep -rl abc .)
But xargs handles well also the case where there are too many arguments for a single call of the command. The above command will give you shell error (argument string too long).
rm doesn't read from standard input (except when prompting, like with -i) but takes its arguments on the command line. That's what xargs does for you: read things from standard input and give them to rm as arguments.
Example with echo:
$ (echo a; echo b; date) | xargs echo
a b tor 12 apr 2018 14:18:50 CEST

Search file name using a variable and replace with another variable

I have search string in one variable ($AUD_DATE) and replace string in another variable ($YEST_DATE). I need to search file name in a folder using $AUD_DATE and then replace it with $YEST_DATE.
I tried using this link to do it but its not working with variables.
Find and replace filename recursively in a directory
shrivn1 $ AUD_DATE=140101
shrivn1 $ YEST_DATE=140124
shrivn1 $ ls *$AUD_DATE*
NULRL.PREM.DATA.CLRSFIFG.140101.dat NULRL.PREM.DATA.CLRTVEH.140101.dat
shrivn1 $ ls *$AUD_DATE*.dat | awk '{a=$1; gsub("$AUD_DATE","$YEST_DATE");printf "mv \"%s\" \"%s\"\n", a, $1}'
mv "NULRL.PREM.DATA.CLRSFIFG.140101.dat" "NULRL.PREM.DATA.CLRSFIFG.140101.dat"
mv "NULRL.PREM.DATA.CLRTVEH.140101.dat" "NULRL.PREM.DATA.CLRTVEH.140101.dat"
Actual output I need is
mv "NULRL.PREM.DATA.CLRSFIFG.140101.dat" "NULRL.PREM.DATA.CLRSFIFG.140124.dat"
mv "NULRL.PREM.DATA.CLRTVEH.140101.dat" "NULRL.PREM.DATA.CLRTVEH.140124.dat"
Thanks in advance
Approach 1
I generally create mv commands using sed and then pipe the output to sh. This approach allows me to see the commands that will be executed beforehand.
For example:
$ AUD_DATE=140101
$ YEST_DATE=140124
$ ls -1tr | grep "${AUD_DATE}" | sed "s/\(.*\)/mv \1 \1_${YEST_DATE}"
Once you are happpy with the output of the previous command;repeat it and pipe it's output to sh, like so:
$ ls -1tr | grep "${AUD_DATE}" | sed "s/\(.*\)/mv \1 \1_${YEST_DATE}" | sh
Approach 2
You could use xargs command.
ls -1tr | grep ${AUD_DATE}" | xargs -I target_file mv target_file target_file${YEST_DATE}

find with grep not working inside shell script

I am using the below command to find the file names and it works fine when execute from command line:
$AIX->: find . | xargs grep -l "BE00036"
./6281723219129
$AIX->:
But the same command is not working when execute from shell script(ksh):
$AIX->: ksh test.ksh
**find: bad option -l**
part of my code is:
Var="find . | xargs grep -l \"BE00036\"
print `$Var`
If you want to assign the output of a command to a variable, you can do
Var="$(find . | xargs grep -l \"BE00036\")"
print "$Var"
This below one works for me:
var=`find . | xargs grep -l 'BE00036'`
echo "$var"

how to pipe commands in ubuntu

How do I pipe commands and their results in Ubuntu when writing them in the terminal. I would write the following commands in sequence -
$ ls | grep ab
abc.pdf
cde.pdf
$ cp abc.pdf cde.pdf files/
I would like to pipe the results of the first command into the second command, and write them all in the same line. How do I do that ?
something like
$ cp "ls | grep ab" files/
(the above is a contrived example and can be written as cp *.pdf files/)
Use the following:
cp `ls | grep ab` files/
Well, since the xargs person gave up, I'll offer my xargs solution:
ls | grep ab | xargs echo | while read f; do cp $f files/; done
Of course, this solution suffers from an obvious flaw: files with spaces in them will cause chaos.
An xargs solution without this flaw? Hmm...
ls | grep ab | xargs '-d\n' bash -c 'docp() { cp "$#" files/; }; docp "$#"'
Seems a bit klunky, but it works. Unless you have files with returns in them I mean. However, anyone who does that deserves what they get. Even that is solvable:
find . -mindepth 1 -maxdepth 1 -name '*ab*' -print0 | xargs -0 bash -c 'docp() { cp "$#" files/; }; docp "$#"'
To use xargs, you need to ensure that the filename arguments are the last arguments passed to the cp command. You can accomplish this with the -t option to cp to specify the target directory:
ls | grep ab | xargs cp -t files/
Of course, even though this is a contrived example, you should not parse the output of ls.

how can i concatenate {}* (star) to xargs and have it refer to it as the special character and not plain character?

I'm performing this
$ ls -l | awk '{print substr($9,substr1,11)}' | uniq | xargs -i ls {}*
ls: cannot access telneter.py*: No such file or directory
ls: cannot access telnetlib.p*: No such file or directory
ls: cannot access threading.p*: No such file or directory
I meant for it to search for files files* however it tells me that it cannot find the files because its actually looking for them with the actual * but i wanted to search for all files by * and not for files ending with *.
anyone can help with this please?
thanks
The * gets in too late to be interpreted by the shell. So, do it in a subshell.
ls -l | awk '{print substr($9,substr1,11)}' | uniq | xargs -i bash -c "ls {}*"

Resources