0

so I'm working on this assignment and I am having trouble with the head command in Unix. Our assignment is to find all of the .txt files within a directory and display the first line of text from each one the output should look like this:

fargo.txt
//first line on the text file here
turtle.txt
//first line on the text file here

and so on

I have the code to find the .txt file in a directory and its sub-directories, but I have to use the head command to display the line of text and I'm lost. using "man head" I don't get very much information about how to use it.

Here's what I got show far

ls ~/Main/* | grep '\.txt'

and I have also tried

ls ~/Main/* | grep '\.txt' `head -n 1`

Any ideas on how to use the "head" command to get the first line of text of these files.

Adrian Heine
  • 4,051
  • 2
  • 30
  • 43
  • You need a `for` loop. Please read [Advanced Bash Scripting Guide](http://www.tldp.org/LDP/abs/html/). Don't expect us to do *your* homework! – Basile Starynkevitch Nov 20 '14 at 05:45
  • Maybe an example of a head command would help me? All I wanted was an example not the answer. I don't think we need a for loop we are not there yet in the course. –  Nov 20 '14 at 05:53
  • Read documentation of [ls(1)](http://man7.org/linux/man-pages/man1/ls.1.html), [head(1)](http://man7.org/linux/man-pages/man1/head.1.html), etc.... – Basile Starynkevitch Nov 20 '14 at 05:55
  • If perfect file name formatting isn't an issue, something like this works as well: `find . -type f -iname '*.txt' -print0 | xargs -0 head -n 1` – Mr. Llama Nov 20 '14 at 16:11

4 Answers4

0

You almost got it right. It's the ls that needs to be enclosed in backticks so that its results are fed as filename arguments to head. To get the first line of all the text files in the current directory you would use:

head -n 1 `ls -Q *.txt`

To get the files in subdirectories, you could use ls and grep like you have (just make ls recursive, and make grep search for .txt in the end of each line), but I suggest you take a look at the find command.

Edit: As mentioned by @jonathanleffler and @unhammer, it is unnecessary to use ls if the files are in one directory. Also, it is a bad idea to use ls in command substitution without the -Q option, because it breaks filenames with spaces in them, but option -Q is not available in most implementations of ls. If you need to search in subdirectories, use find (or **/*.txt if your shell supports it, as suggested by Jonathan).

Edit 2: Since the OP already got pretty close with the find command, I'll add my solution here:

find . -name "*.txt" -print -exec head -n 1 "{}" \;
mhavu
  • 41
  • 7
  • 1
    No need for the `ls`; not using it avoids problems with file names with spaces. – Jonathan Leffler Nov 20 '14 at 06:58
  • Indeed. The backticks and `ls` are only necessary for the recursive case, but `find` is the better choice there. – mhavu Nov 20 '14 at 07:22
  • 1
    In `bash` (which is not stipulated in the question), with Bash 4.x (4.3 tested) and `shopt -s globstar` enabled, you'd use [`**/*.txt`](http://www.gnu.org/software/bash/manual/bash.html#Filename-Expansion) to generate the list of file names directly in the shell. – Jonathan Leffler Nov 20 '14 at 07:55
0

In case you have files with spaces in their name, the following should resist :

for file in *.txt
do 
    echo "$i" 
    head -1 "$i"
done
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • $i should be quoted when sent to echo as well (you don't want your computer to go "ding" because someone thought it was fun to name a file '-e \a.txt'). Also, it's superfluous – head itself writes the name of the file if you give it multiple files. – unhammer Nov 20 '14 at 07:03
0

I know I'm probably finishing someones homework here, but please don't do

head -n 1 `ls *.txt`

– it will fail if there are files containing spaces. And you can't quote it, because then it treats all the output as one file.

The correct way to show the first line of all the[1] .txt files in the current directory is:

head -n 1 *.txt

(for some other folder, head -n 1 /other/folder/*.txt). This will work with all kinds of strange file names because the shell itself correctly sends in the right file names to the head command.

And head is smart enough to tell that you want to see the file name in the output when you pass it several files.


[1] Well, actually it's head -n 1 *.txt .*.txt because plain *.txt doesn't include files that start with a dot.

unhammer
  • 4,306
  • 2
  • 39
  • 52
0

Hey guys I figured out the answer; this is what the assignment was looking for:

find ~/Main -name '*.txt' -head -exec {} \;
  • I think you mean `find ~/Main -name '*.txt' -exec head -n 1 {} \;` – though this won't show the filenames, for that you need to do `find ~/Main -name '*.txt' -print -exec head -n 1 {} \;` – unhammer Nov 23 '14 at 08:22