As goldilocks’ comment and humanity’s references describe,
shift
reassigns the positional parameters ($1
, $2
, etc.)
so that $1
takes on the old value of $2
,
$2
takes on the value of $3
, etc.*
The old value of $1
is discarded. ($0
is not changed.)
Some reasons for doing this include:
- It lets you access the tenth argument (if there is one) more easily.
$10
doesn’t work – it’s interpreted as $1
concatenated with a 0
(and so might produce something like Hello0
).
After a shift
, the tenth argument becomes $9
.
(However, in most modern shells, you can use ${10}
.)
- As the Bash Guide for Beginners demonstrates,
it can be used to loop through the arguments.
IMNSHO, this is clumsy;
for
is much better for that.
- As in your example script,
it makes it easy to process all of the arguments the same way except for a few.
For example, in your script,
$1
and $2
are text strings,
while $3
and all other parameters are file names.
So here’s how it plays out.
Suppose your script is called Patryk_script
and it is called as
Patryk_script USSR Russia Treaty1 Atlas2 Pravda3
The script sees
$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = Atlas2
$5 = Pravda3
The statement ostr="$1"
sets variable ostr
to USSR
.
The first shift
statement changes the positional parameters as follows:
$1 = Russia
$2 = Treaty1
$3 = Atlas2
$4 = Pravda3
The statement nstr="$1"
sets variable nstr
to Russia
.
The second shift
statement changes the positional parameters as follows:
$1 = Treaty1
$2 = Atlas2
$3 = Pravda3
And then the for
loop changes USSR
($ostr
) to Russia
($nstr
)
in the files Treaty1
, Atlas2
, and Pravda3
.
There are a few problems with the script.
for file in $@; do
If the script is invoked as
Patryk_script USSR Russia Treaty1 "World Atlas2" Pravda3
it sees
$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = World Atlas2
$5 = Pravda3
but, because $@
isn’t quoted, the space in World Atlas2
isn’t quoted,
and the for
loop thinks it has four files: Treaty1
, World
, Atlas2
,
and Pravda3
.
This should be either
for file in "$@"; do
(to quote any special characters in the arguments) or simply
for file do
(which is equivalent to the longer version).
eval "sed 's/"$ostr"/"$nstr"/g' $file"
There’s no need for this to be an eval
,
and passing unchecked user input to an eval
can be dangerous.
For example, if the script is invoked as
Patryk_script "'; rm *;'" Russia Treaty1 Atlas2 Pravda3
it will execute rm *
!
This is a big concern if the script can be run
with privileges higher than those of the user who invokes it;
e.g., if it can be run via sudo
or invoked from a web interface.
It’s probably not so important if you just use it as yourself,
in your directory.
But it can be changed to
sed "s/$ostr/$nstr/g" "$file"
This still has some risks, but they are much less severe.
if [ -f $file ]
, > $file.tmp
and mv $file.tmp $file
should be if [ -f "$file" ]
, > "$file.tmp"
and mv "$file.tmp" "$file"
,
respectively, to handle file names
that might have spaces (or other funny characters) in them.
(The eval "sed …
command also mangles file names that have spaces in them.)
* shift
takes an optional argument:
a positive integer that specifies how many parameters to shift.
The default is one (1
).
For example, shift 4
causes $5
to become $1
,
$6
to become $2
, and so on.
(Note that the example in the Bash Guide for Beginners is wrong.)
And so your script could be modified to say
ostr="$1"
nstr="$2"
shift 2
which might be considered to be more clear.
End Note / Warning:
The Windows Command Prompt (batch file) language
also supports a SHIFT
command,
which does basically the same thing as the shift
command in Unix shells,
with one striking difference,
which I’ll hide to try to prevent people from being confused by it:
- A command like
SHIFT 4
is an error,
yielding an “Invalid parameter to SHIFT command” error message.
SHIFT /n
, where n
is an integer between 0 and 8,
is valid — but it doesn’t shift n
times.
It shifts once, starting with the n th argument.
So SHIFT /4
causes %5
(the fifth argument) to become %4,
%6
to become %5
, and so on, leaving arguments 0 through 3 alone.
pushd
andpopd
). – goldilocks Dec 16 '14 at 22:10bash
, the question is general to all shells, therefore the Posix standard prevails: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set – calandoa Aug 14 '19 at 11:00