Pipelining of cat and ls commands [duplicate] - linux

This question already has answers here:
Unix pipe into ls
(3 answers)
Closed 6 years ago.
I am a newbie to linux . I have been learning about cat command when i tried this .
harish#harish-Lenovo-G50-45:~$ cat file
Videos/Arrow/Season*
harish#harish-Lenovo-G50-45:~$ cat file | ls -l
The command displays the content of the current folder instead of the folder mentioned in the file .. But when i did this
harish#harish-Lenovo-G50-45:~$ cat file
Videos/Arrow/Season*
harish#harish-Lenovo-G50-45:~$ ls -l $(cat file)
The contents of the expected folder displays correctly . Why cant i not use the pipeline in this case ?

In the first example you are passing the output of cat file to the input of ls -l. Since ls -l does not take any input, it does not do anything regarding the output of cat file. However in the second example you are using $(cat file) which puts the output of cat file in the place of an argument passed to ls -l, and this time ls -l has the text inside file in the right place for doing something with it. The issue here is noticing the difference between the standard input of a program and the arguments of a program. Standard input is what you have when you call scanf in C, for example; and the arguments are what you get in the argv pointer passed as parameter to the main procedure.

Related

Why does touch $(ls).bla create only one file

Well in one directory I have 24 files but when I run the above command it makes only one file, but if i type echo $(ls) it lists all files
Guess, you mixed up the file expansion. Try this:
echo $(ls *.bla)
touch $(ls *.bla)
Here is an example of what is happening when running $ touch "$(ls).bla" in a folder containing a single file foo that illustrates what is happening:
$ ls
foo
$ touch "$(ls).bla"
$ ls
foo foo.bla
$ touch "$(ls).bla"
$ ls
foo 'foo'$'\n''foo.bla.bla' foo.bla
As you can see the first time the touch command is called it creates a single file named foo.bla. When creating a subshell with $(ls) as the argument the touch command will get that as a single command line parameter not multiple ones. That is why the second time touch "$(ls).bla" is run above the result yields a single file with a strange filename.
What you probably want if you want to create empty files with the same name as other files in a folder is to pipe the output of ls to xargs like this:
$ ls | xargs -i touch "{}.bla"
The -i flag to xargs causes it to replace {} with the file names it gets from ls.

How to specify more inputs as a single input in Linux command-line?

I searched online but I didn't find anything that could answer my question.
I'm using a java tool in Ubuntu Linux, calling it with bash command; this tool has two paths for two different input files:
java -Xmx8G -jar picard.jar FastqToSam \
FASTQ=6484_snippet_1.fastq \ #first read file of pair
FASTQ2=6484_snippet_2.fastq \ #second read file of pair
[...]
What I'd like to do is for example, instead of specify the path of a single FASTQ, specify the path of two different files.
So instead of having cat file1 file2 > File and using File as input of FASTQ, I'd like that this operation would be executed on the fly and create the File on the fly, without saving it on the file system (that would be what happens with the command cat file1 file2 > File).
I hope that I've been clear in explaining my question, in case just ask me and I'll try to explain better.
Most well-written shell commands which accept a file name argument also usually accept a list of file name arguments. Like cat file or cat file1 file2 etc.
If the program you are trying to use doesn't support this, and cannot easily be fixed, perhaps your OS or shell makes /dev/stdin available as a pseudo-file.
cat file1 file2 | java -mumble -crash -burn FASTQ=/dev/stdin
Some shells also have process substitutions, which (typically) look to the calling program like a single file containing whatever the process substitution produces on standard output.
java -mumble -crash -burn FASTQ=<(cat file1 file2) FASTQ2=<(cat file3 file4)
If neither of these work, a simple shell script which uses temporary files and deletes them when it's done is a tried and true solution.
#!/bin/sh
: ${4?Need four file name arguments, will process them pairwise}
t=$(mktemp -d -t fastqtwoness.XXXXXXX) || exit
trap 'rm -rf $t' EXIT HUP INT TERM # remove in case of failure or when done
cat "$1" "$2" >$t/1.fastq
cat "$3" "$4" >$t/2.fastq
exec java -mumble -crash -burn FASTQ=$t/1.fastq FASTQ2=$t/2.fastq

Linux Command : Why does the redirection operator - | i.e. piping fail here?

I was working my way through a primer on Shell (Bash) Scripting and had the following doubt :
Why does not the following command print the contents of cp's directory : which cp | ls -l
Does not piping by definition mean that we pass the output of one command to another i.e. redirect the output ?
Can someone help me out ? I am a newbie ..
The output of which is being piped to the standard input of ls. However, ls doesn't take anything on standard input. You want it (I presume) to be passed as a parameter. There are a couple of ways of doing that:
which cp | xargs ls -l
or
ls -l `which cp`
or
ls -l $(which cp)
In the first example the xargs command takes the standard output of the previous previous command and makes each line a parameter to the command whose name immediately follows xargs. So, for instance
find / | xargs ls -l
will do an ls -l on each file in the filesystem (there are some issues with this with peculiarly named files but that's beyond the scope of this answer).
The remaining two are broadly equivalent and use the shell to do this, expanding the output from which into the command line for cp.
It would be,
$ ls -l $(which cp)
-rwxr-xr-x 1 root root 130304 Mar 24 2014 /bin/cp
OR
$ which cp | xargs ls -l
-rwxr-xr-x 1 root root 130304 Mar 24 2014 /bin/cp
To pass the output of one command as parameter of another command, you need to use xargs along with the pipe symbol.
From man xargs
xargs - build and execute command lines from standard input.xargs reads items
from the standard input, delimited by blanks (which can be protected
with double or single quotes or a backslash) or newlines, and executes
the command (default is /bin/echo) one or more times with any initial-
arguments followed by items read from standard input. Blank lines on
the standard input are ignored.

linux bash redirection with stdin and stdout the same file [duplicate]

This question already has answers here:
How can I use a file in a command and redirect output to the same file without truncating it?
(14 answers)
Closed 8 years ago.
i have a problem about bash, command is like:
echo helloworld > hello.txt
cat <hello.txt >hello.txt
at first, there are stuff in hello.txt. what i expect is that it should seem nothing happens to hello.txt after executing the command, but there is nothing in hello.txt then.
is it a mechanism of bash, or is there something i did not understand about linux file descripor?
maybe bash establish only one fd for a certain file? am i right?
can you help me?
/br
ruan
Use a temporary file
cat hello.txt > /var/tmp/tmpFile
mv -f /var/tmp/tmpFile hello.txt
cat hello.txt

Launching program several times

I am using Mac Os. This is command line code to lauch my programm (two parts)
nucmer --mum file1.txt file2.txt
show-snps -Clr -x 2 out.delta > out_file1.snps
First part of the programm creates file out.delta. My file2.txt is always the same, but I want to launch this both parts 35000 times whith different file1.txt. All the file1s are located in the same directory.
Is it possible to do it using BASH?
Keep all the input files in a directory. Create a wrapper script to invoke nucmer script and then show-snps script. Your wrapper script will accept path to file directory as input. Iterate over all files in the directory and call your two scripts.
You could do something along these lines:
find . -maxdepth 1 -type f -print | grep -v './out_' | while read f
do
b=$(basename ${f})
nucmer --mum ${f} file2.txt
show-snps -Clr -x 2 out.delta > out_${b}.snps
done
The find bit finds all files in the current directory. grep filters out any previous output files, in case you've run some previously. The basename line strips off the leading ./ and trailing extension, and then your two programs get run with the input file name and an output filename based on the basename output.
If you don't get an argument list too long error, you could just use for:
for f in file*.txt; do nucmer --mum $f second.txt; show-snps -Clr -x 2 out.delta > out_${f%.txt}.snps; done

Resources