Script to move the first line of a file to the end

I'm rather new to scripting, and despite my attempts at finding/writing a script to do what I need, I have not yet been successful.

I have a file named "list.txt" of arbitrary length with contents in the following format:

/home/user/Music/file1.mp3
/home/user/Music/file2.mp3
/home/user/Music/file3.mp3
/home/user/Music/file5.txt
/home/user/Music/file7.wav
/home/user/Music/file11.ogg
/home/user/Music/file13.m4a

I would like a script that will change the contents of "list.txt" to:

/home/user/Music/file2.mp3
/home/user/Music/file3.mp3
/home/user/Music/file5.txt
/home/user/Music/file7.wav
/home/user/Music/file11.ogg
/home/user/Music/file13.m4a
/home/user/Music/file1.mp3

Basically, I need the first line moved to the end. I don't care whether it's in bash, awk, sed, perl, or whatever scripting language as long as it works.

What is your attempt - you should show that first ?

Here is a sample

awk '{ if ( NR == 1 ) { store=$0 } else { print } }END{ print store }' filename

using Perl:

# first_to_last.pl
my $file = shift;
open(FH, '<', $file)  or  die "Failed to read file $file : $! \n";
my $first_line      = <FH>;
my @remaining_lines = <FH>;
close(FH);

open(FH, '>', $file)  or  die "Failed to write file $file : $! \n";
print FH @remaining_lines;
print FH $first_line;
close(FH);

run this script as:

perl first_to_last.pl list.txt

Why do you want to load the entire file into memory ( almost entire except for the first line ). Won't that be enough to store the first line and print the rest as and when its being read?

awk 'NR==1{store=$0;next}1;END{print store}' file

Thanks. That works exactly as I need it to.

That does what I need it to, but it outputs the results to the console, whereas I need it to output it back to the file. I tried setting it equal to a variable and outputting that to a file, but that output the contents of the file separated by spaces rather than line breaks.

Here's what I tried:

#!/bin/bash
var=`awk 'NR==1{store=$0;next}1;END{print store}' list.txt`
echo $var > list.txt
$ cat ./list.txt
1
2
3
4
5
6
$ ./first_to_last.sh
$ cat ./list.txt
2 3 4 5 6 1
{
  IFS= read -r line
  cat
  printf "%s\n" "$line"
} < "$FILE" > tempfile && mv tempfile "$FILE"

What about:

echo "$var" > list.txt

Or use "sed" to copy lines 2 onwards, then get the first line with "head -1".

#!/bin/ksh
cat list.txt | sed -n "2,\$ p" >new_list.txt
head -1 list.txt >> new_list.txt

This is UUOC, cat is not needed here

just sed '<operation>' filename would do

Nor is head required:

IFS= read -r line < list.txt
printf "%s\n" "$line" >> new_list.txt

It is possible to write scripts which might work efficiently but are unintelligible to newbies. The previous post with "IFS" is a classic.
We may post examples which are easy to follow rather than what we might use in a commercial environment. Most people find left-to-right date flow easier to follow.

IMHO the best outline design is the compact "awk" program which the poster tried but got the wrong results. It needs adjusting to not put the whole file into a variable called $var, but to write directly to the new file instead. This could be done from "awk" itself, but here is a way with shell redirect.

awk 'NR==1{store=$0;next}1;END{print store}' list.txt >new_list.txt

In a production script you would probably then copy "list.txt" before overwriting it with "new_list.txt" .

Its better to get various forms of getting it to work, as the saying goes " many ways to skin a cat " ( no uuoc here :wink: )

Initially for a newbie it might be of interest to get the task done and later it might be interesting and a good learning experience to make it better, optimal without having to spawn too many processes where it could be achieved by shell built-ins etc.

I fully agree with matrixmadham. Whether on unix , DOS, VME or whatever building shell programs is best learnt step-by-step with prototype scripts and examples which can then be improved with experience.
Each year we will find a move towards a fashionable standard. Whatever happened to OS-9 and DCL as universal scripting languages? We are learning from cfajohnson of a move towards Posix-2 , but to get "normal" Berkeley behaviour from commands such as "ps" and "xd" we often need to go outside Posix-2 and even the less-strict XPG4 standard.

When we work on multiple unix/Linux/etc. platforms it is useful to learn portable scripting techniques and to be aware of useful commands that are not always implemented like Linux "stat", or can have differerent syntax like "echo", or can have a mishmash of variations like "awk" and "nawk".

IMHO we will still be debating standards up to 18/01/2038 (the Y2K38 problem).

That line is the only way to guarantee reading an entire line. No one but a total newbie should have any problem with it.

There used to be a line command that did the same thing, but that is rarely found these days.

I have to agree. I any case to know the purpose of, and have some concept of the effect of the manipulation of IFS is something that a new scripter would be well advised to learn. It can make some tasks truly trivial.

When manipulating records with shell it is good practice to never put the record into a shell variable. We've had examples on this board where the data has changed because the record contained characters recognised by the shell (e.g. reverse solidus).
Obviously with known valid data there is no problem.

sed -n '1 {
h
}
1 !{
$ !{
p
}
$ {
p
x
p
}
}' a.txt

Hi.

Useful for small files, the simple editor, ed, has a move command:

#!/bin/bash -

# @(#) s1       Demonstrate editing file in place with script-able line editor, ed.

echo
echo "(Versions displayed with local utility \"version\")"
version >/dev/null 2>&1 && version "=o" $(_eat $0 $1) ed
set -o nounset
echo

FILE=${1-data1}

cp original $FILE
echo " Data file $FILE:"
cat $FILE

echo
echo " Messages from ed:"
ed $FILE <<EOF
1m$
w
q
EOF

echo
echo " Modified data file $FILE:"
cat $FILE

exit 0

Producing:

% ./s1

(Versions displayed with local utility "version")
Linux 2.6.11-x1
GNU bash
GNU ed version 0.2

 Data file data1:
/home/user/Music/file1.mp3
/home/user/Music/file2.mp3
/home/user/Music/file3.mp3
/home/user/Music/file5.txt
/home/user/Music/file7.wav
/home/user/Music/file11.ogg
/home/user/Music/file13.m4a

 Messages from ed:
191
191

 Modified data file data1:
/home/user/Music/file2.mp3
/home/user/Music/file3.mp3
/home/user/Music/file5.txt
/home/user/Music/file7.wav
/home/user/Music/file11.ogg
/home/user/Music/file13.m4a
/home/user/Music/file1.mp3

See man ed for details on the editing commands ... cheers, drl

eg : a.txt
a
b
c
d
e
f

execute this script :

vi - a.txt <<END
:mv 1 $
:x
<<END