Use ls to show only certain number of items - unix

I'm trying to get a simple myhead command in C to show the top 10 lines of the first five .HTML files in a directory. I was advised to use ls to carry this out in conjunction with my myhead command. My main issue is with getting ls to only show 5 .html files and not list them all.
I was thinking something like this
ls *.html -n 5 > myhead
However, that doesn't exist. Any ideas? We are only meant to use ls and myhead.

If I understand correctly, you've written a C program myhead that prints out ten lines of a file passed in.
You definitely don't want to do this
ls *.html -n 5 > myhead
This would overwrite or create a new file myhead in the current directory.
The key thing needed to achieve this are command line pipes. This allows the stdout of one command to be the stdin of the next command. Also you'll need command substitution which is having the stdout output of one command, or piped commands, be used as text for another command. Historically this has been done with backticks `ls`, or in bash you can use $(ls) as an example to get a ls listing and use it as text for another command.
Given you're okay with the standard ls file list order you can do this to get the first 5 .html files:
ls *.html | head -n 5
I don't know what myhead is or how it works as it's not explained in the question. You say it shows the first ten lines of a file passed into it. There could be a few it does that.
I'll give a solution for each possibility (assuming you're using bash):
take one file at a time, passed in as an argument
for f in $(ls *.html | head -n 5) ; do myhead $f ; done
take multiple files at a time, passed in as multiple arguments
myhead $(ls *.html | head -n 5)
take the contents of a file passed in through stdin
for f in $(ls *.html | head -n 5) ; do cat $f | myhead ; done

What you're looking for are pipes
You can use them like this:
# all the output (STDOUT) of ls is passed as the input (STDIN) of myhead
ls *.html | myhead -5
myhead reads the input on STDIN, and outputs N lines of it on STDOUT.

With the standard Unix head command, you can do this:
head -n 10 $(ls | head -n 5)
First, you should run this command exactly as shown in your shell to verify it works. Next, try it with your myhead command instead of head.

Related

Piping the results of *nix commands into Vim's set of open files

I have a folder resembling this structure:
nietzsche.txt
kant.org
buddha.txt
kierkegaard.org
aristotle.txt
plato.org
I wish to read the text files that have the *.org extension, so I use the command:
ls | grep .org
The above command neatly sends the following to stdin:
> kant.org
> kierkegaard.org
> plato.org
I would like to open the files listed above in vim all at once - with the above given example, this is trivial; it would just mean typing out the list of files prefixed with "vim", for example:
vim kant.org kierkegaard.org plato.org
...but in my actual folder of articles there are several hundred plain text files, with the *.org and the *.txt extension. It isn't a matter of converting the org files to true plain text, it's trying to get vim to use the output of other commands through pipes. In reality, the conditions for generating the "books-to-read" list are far more complicated (ie. using date last read, author, date written etc) so a simple find and replace of org-to-txt wouldn't work, as I currently have a bash script to generate the list and spit it to stdout.
How would I get vim to accept the output of a command like grep as a list of files to open immediately?
In this specific example, ls | grep .org is pointless since you can simply do:
$ vim *.org
As for the general case, you would use $ man xargs on Unix-like systems:
$ <command that generates a list of files> | xargs -o vim
or:
$ <command that generates a list of files> | xargs vim --not-a-term
Note that xargs' -o and Vim's --not-a-term are more or less the opposite of each other. The former ensures that xargs passes a proper tty to Vim, while the latter ensures that Vim doesn't complain if there is no attached tty.
You can use command mode completion inside vim:
:e *.org<C-a>
Read more on :h c_CTRL-A

In Unix, how do I display the contents of all files that begin with a prefix?

a bunch of text files that start with the prefix r_ , and I want to display the contents of all these files at once.
I tried to use cat and a command like this :
cat [f_*] ,
But this doesn't work like I expect
Using that cat properly:
$ cat r_*
As there is some mixup in the OP about the starting letter, go ahead and use this: cat [fr]_* .
you can use tail or head commands,
tail -n +1 r_*
You can use a script something like this
path="<Your Path Here>"
find $path -name "r_*" | while read -r currentFile;
do
while read -r line;
do
HERE $line will be each line
done < $currentFile
done
Here find $path -name "r_*" will find all the files starting with a r_ in the given path and iterate each file one by one.
The loop while read -r line will read each line content for you to perform any action

Print labels using awk

On my FreeBSD 10.1 I'm writing a little piece of code that basically calls ls and automatically breaks the results down into something like this:
directory:
2.4M .git
528K src
380K dist
184K test
file:
856K CONDUCT.md
20K README.md
........
You will only need to list out directories and regular files, and you don't have to list out . .., but you have to list out hidden files, and sort them from largest to smallest separately.
The challenge is to complete it as a one-line command without using $(cmd), &&, ||, >, >>, <, ;, & and within 12 pipes (back quotes count as well).
Currently my progress is:
ls -Alh | sort -d -h -r |
awk 'BEGIN {print "Directories:"}
NR>1 {if(substr($1,1,1)~"d")print" "$5" "$9}'
which prints out only until the last directory item. But since the entire command will output once every record, I can't find a way to print files: only once, and then print out the remaining output.
Well, you may have to store the files in an array and print at the end:
ls -Alh|sed 1d|
sort -h -k5r|
awk 'BEGIN {print "Directories:"}
/^d/{print "\t"$5"\t"$9}
/^-/{f[n++]=sprintf("\t"$5"\t"$9)}
END{print "Files:";
for(i=0;i<n;++i)print f[i]}'
One additional problem you'll need to work out: files and dirs may have spaces in the name, and the simple $9 will be insufficient for that case.

How to cat using part of a filename in terminal?

I'm using terminal on OS 10.X. I have some data files of the format:
mbh5.0_mrg4.54545454545_period0.000722172513951.params.dat
mbh5.0_mrg4.54545454545_period0.00077271543854.params.dat
mbh5.0_mrg4.59090909091_period-0.000355232058085.params.dat
mbh5.0_mrg4.59090909091_period-0.000402015664015.params.dat
I know that there will be some files with similar numbers after mbh and mrg, but I won't know ahead of time what the numbers will be or how many similarly numbered ones there will be. My goal is to cat all the data from all the files with similar numbers after mbh and mrg into one data file. So from the above I would want to do something like...
cat mbh5.0_mrg4.54545454545*dat > mbh5.0_mrg4.54545454545.dat
cat mbh5.0_mrg4.5909090909*dat > mbh5.0_mrg4.5909090909.dat
I want to automate this process because there will be many such files.
What would be the best way to do this? I've been looking into sed, but I don't have a solution yet.
for file in *.params.dat; do
prefix=${file%_*}
cat "$file" >> "$prefix.dat"
done
This part ${file%_*} remove the last underscore and following text from the end of $file and saves the result in the prefix variable. (Ref: http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion)
It's not 100% clear to me what you're trying to achieve here but if you want to aggregate files into a file with the same number after "mbh5.0_mrg4." then you can do the following.
ls -l mbh5.0_mrg4* | awk '{print "cat " $9 " > mbh5.0_mrg4." substr($9,12,11) ".dat" }' | /bin/bash
The "ls -s" lists the file and the "awk" takes the 9th column from the result of the ls. With some string concatenation the result is passed to /bin/bash to be executed.
This is a linux bash script, so assuming you have /bind/bash, I'm not 100% famililar with OS X. This script also assumes that the number youre grouping on is always in the same place in the filename. I think you can change /bin/bash to almost any shell you have installed.

Run a command multiple times with arguments given from standard input

I remember seeing a unix command that would take lines from standard input and execute another command multiple times, with each line of input as the arguments. For the life of me I can't remember what the command was, but the syntax was something like this:
ls | multirun -r% rm %
In this case rm % was the command to run multiple times, and -r% was an option than means replace % with the input line (I don't remember what the real option was either, I'm just using -r as an example). The complete command would remove all files in the current by passing the name of each file in turn to rm (assuming, of course, that there are no directories in the current directory). What is the real name of multirun?
The command is called 'xargs' :-) and you can run it as following
ls | xargs echo I would love to rm -f the files

Resources