Is there a way to 'inject' a command line output into another command? - bash

for ex :
grep -R "requests" /some/really/long/path/to/type/out
I would like to do something like this
grep -R "requests" (pwd)
Basically, using the output of pwd sorta like a pipe (pipe dosent do it).

Use command substitution:
grep -R "requests" $(pwd)
The output of the command in $(...) is used as an argument list to the command. If you want the output to be treated as one word, wrap it in double quotes:
ls "$( command-that-produces-dirname-containing-whitespace )"

In bash you can use backtics for this:
grep -R "requests" `pwd`
pwd will be executed and the stdout of pwd will be used as the third parameter of the grep command

Related

How to concat pipe result with next command?

I would like to run something like :
pwd | echo "++++ working at : $x"
and the $x variable would show the current directory. I've tried a kind of $(...) stuff with no success.
It has to be in one line to be run in a Dockerfile
BASH gives you an env variable called PWD denoting current working directory hence there is no need to call any external utility just use:
echo "++++ working at : $PWD"
could use xargs
pwd | xargs -I{} echo "++++ working at : {}"
Alternatively you could just not use a pipe and use a subshell
echo "++++ working at : $(pwd)"
backticks to the rescue!
echo "++++ working at : " `pwd`
backticks mean: put the command output right here in the command line as argument(s)

echo to standard input or stdin

How can I echo to stdin?
For example, I have an alias called 'replace'. When I run 'replace' it should echo
sed 's/~/~\\n/g'
into my command line. Notice the sed command above doesn't have a file target. I'll supply the file target after it echos the sed into the command line.
Create alias like this:
alias replace="sed 's/~/~\\n/g' "
And then run it like this:
replace file
PS: It won't echo the full sed command on your tty but it will effectively run:
sed 's/~/~\\n/g' file
EDIT: On your question of echoing command before executing. Create a script sedscript.sh like this:
set -x
# do some sanity check on $1
sed 's/~/~\\n/g' "$1"
Now have you alias like this:
chmod +x sedscript.sh
alias replace="/path/to/sedscript.sh "
Now every time you run:
replace file
It will echo this line before sed command execution:
++ sed 's/~/~\\n/g' file

How to refer to redirection file from within a bash script?

I'd like to write a bash script myscript such that issuing this command:
myscript > filename.txt
would return the name of the filename that it's output is being redirected to, filename.txt. Is this possible?
If you are running on Linux, check where /proc/self/fd/1 links to.
For example, the script can do the following:
#!/bin/bash
readlink /proc/self/fd/1
And then run it:
$ ./myscript > filename.txt
$ cat filename.txt
/tmp/filename.txt
Note that if you want to save the value of the output file to a variable or something, you can't use /proc/self since it will be different in the subshell, but you can still use $$:
outputfile=$(readlink /proc/$$/fd/1)
Using lsof:
outfile=$(lsof -p $$ | awk '/1w/{print $NF}')
echo $outfile

Replace script works if I type manually but not in script

I have a bash script, replace.sh with the following contents:
ack-grep -a -l -i --print0 --text "$1" | xargs -0 -n 1 sed -i -e 's/$1/$2/g'
When I try and run it as, eg:
replace.sh something somethingnew
The prompt returns without errors but no changes have been made to any files.
If I manually type:
ack-grep -a -l -i --print0 --text "something" | xargs -0 -n 1 sed -i -e 's/something/somethingelse/g'
The files get changed as expected.
Ths $1 syntax seems to work for other scripts I've written. I'm guessing I'm missing something to do with escaping the args or something?
Thanks!
Ludo.
Variable substitutions aren't done in single quotes, try:
ack-grep -a -l -i --print0 --text "$1" | xargs -0 -n 1 sed -i -e "s/$1/$2/g"
See the bash man page section on QUOTING.
Use "" instead of '' in the sed expression. It will not prevent the variablename-resolving. What you are actually doing now is replacing $1 to $2. You can test in console (without writing a script) like this:
$ a=something
$ b=somethingelse
$ sed 's/$a/$b/g' testfile
$ sed "s/$a/$b/g" testfile
This isn't related to your question, but some help on using ack.
The -a and --text conflict with each other. -a will give you a superset of --text. Use one or the other.
Also, it looks like you might as well use grep -Z instead of ack since you're not using any of ack's functionality that is a superset of grep.
In general, if you're using ack in a pipeline, you should probably be using good ol' grep instead.

Using xargs to assign stdin to a variable

All that I really want to do is make sure everything in a pipeline succeeded and assign the last stdin to a variable. Consider the following dumbed down scenario:
x=`exit 1|cat`
When I run declare -a, I see this:
declare -a PIPESTATUS='([0]="0")'
I need some way to notice the exit 1, so I converted it to this:
exit 1|cat|xargs -I {} x={}
And declare -a gave me:
declare -a PIPESTATUS='([0]="1" [1]="0" [2]="0")'
That is what I wanted, so I tried to see what would happen if the exit 1 didn't happen:
echo 1|cat|xargs -I {} x={}
But it fails with:
xargs: x={}: No such file or directory
Is there any way to have xargs assign {} to x? What about other methods of having PIPESTATUS work and assigning the stdin to a variable?
Note: these examples are dumbed down. I'm not really doing an exit 1, echo 1 or a cat, but used these commands to simplify so we can focus on my particular issue.
When you use backticks (or the preferred $()) you're running those commands in a subshell. The PIPESTATUS you're getting is for the assignment rather than the piped commands in the subshell.
When you use xargs, it knows nothing about the shell so it can't make variable assignments.
Try set -o pipefail then you can get the status from $?.
xargs is run in a child process, as are all the commands you call. So they can't effect the environment of your shell.
You might be able to do something with named pipes (mkfifo), or possible bash's read function?
EDIT:
Maybe just redirect the output to a file, then you can use PIPESTATUS:
command1 | command2 | command3 >/tmp/tmpfile
## Examine PIPESTATUS
X=$(cat /tmp/tmpfile)
How about ...
read x <<<"$(echo 1)"
read x < <(echo 1)
echo "$x"
Why not just populate a new array?
IFS=$'\n' read -r -d '' -a result < <(echo a | cat | cat; echo "PIPESTATUS='${PIPESTATUS[*]}'" )
IFS=$'\n' read -r -d '' -a result < <(echo a | exit 1 | cat; echo "PIPESTATUS='${PIPESTATUS[*]}'" )
echo "${#result[#]}"
echo "${result[#]}"
echo "${result[0]}"
echo "${result[1]}"
There are already a few helpful solutions. It turns out that I actually had an example that matches the question as framed above; close-enough anyway.
Consider this:
XX=$(ls -l *.cpp | wc -l | xargs -I{} echo {})
echo $XX
3
Meaning that I had 3 x .cpp files to in my working directory. Now $XX is 3 and I can make use of that result in my script. It is contrived, because I don't actually need the xargs in this example. It works though.
In the example from the question ...
x=`exit 1|cat`
I don't think that will give you what was specified. exit will quit the sub-shell before the cat gets a mention. Also on that note,
I might start with something like
declare -a PIPESTATUS='([0]="0")'
x=$?
x now has the status from the last command.
Assign each line of input to an array, e.g. all python files in a directory
declare -a pyFiles=($(ls -l *.py | awk '{print $9}'))
where $9 is the nineth field in ls -l corresponding to the filename

Resources