Я сталкивался с этим сценарием:
#! /bin/bash
if (( $# < 3 )); then
echo "$0 old_string new_string file [file...]"
exit 0
else
ostr="$1"; shift
nstr="$1"; shift
fi
echo "Replacing \"$ostr\" with \"$nstr\""
for file in $@; do
if [ -f $file ]; then
echo "Working with: $file"
eval "sed 's/"$ostr"/"$nstr"/g' $file" > $file.tmp
mv $file.tmp $file
fi
done
В чем смысл линий, где они используются shift
? Я предполагаю, что сценарий должен использоваться по крайней мере с аргументами, так что ...?
shell-script
arguments
Patryk
источник
источник
pushd
иpopd
).bash
, вопрос является общим для всех оболочек, поэтому стандарт Posix превалирует: pubs.opengroup.org/onlinepubs/9699919799/utilities/…Как комментарий Златовласка и ссылки человечества описывают,
shift
переназначение позиционных параметров ($1
,$2
и т.д.) , так что$1
берет на старое значение$2
,$2
принимает значения$3
, и т.д. * Старое значение$1
отбрасывается. ($0
не изменено.) Некоторые причины для этого включают в себя:$10
не работает - он интерпретируется как$1
сцепленный с0
(и может привести к чему-то вродеHello0
). Послеshift
, десятый аргумент становится$9
. (Тем не менее, в большинстве современных оболочек вы можете использовать${10}
.)for
намного лучше для этого.$1
и$2
текстовые строки, тогда как$3
и все остальные параметры являются именами файлов.Вот как это закончится. Предположим, ваш скрипт называется
Patryk_script
и называетсяСкрипт видит
Оператор
ostr="$1"
устанавливает переменнуюostr
вUSSR
. Первыйshift
оператор изменяет позиционные параметры следующим образом:Оператор
nstr="$1"
устанавливает переменнуюnstr
вRussia
. Второйshift
оператор изменяет позиционные параметры следующим образом:И тогда
for
изменения циклаUSSR
($ostr
) вRussia
($nstr
) в файлахTreaty1
,Atlas2
иPravda3
.Есть несколько проблем со сценарием.
Если скрипт вызывается как
это видит
но, потому что
$@
не котируются, пространство вWorld Atlas2
не котируются, иfor
цикл думает , что имеет четыре файла:Treaty1
,World
,Atlas2
иPravda3
. Это должно быть либо(цитировать любые специальные символы в аргументах) или просто
(что эквивалентно более длинной версии).
Нет необходимости, чтобы это было
eval
, и передача непроверенного пользовательского вводаeval
может быть опасной. Например, если скрипт вызывается какэто выполнит
rm *
! Это большая проблема, если скрипт может быть запущен с привилегиями выше, чем у пользователя, который его вызывает; например, если он может быть запущен черезsudo
или вызван из веб-интерфейса. Вероятно, это не так важно, если вы просто используете его в своем каталоге. Но это можно изменить наЭто все еще имеет некоторые риски, но они гораздо менее серьезны.
if [ -f $file ]
,> $file.tmp
иmv $file.tmp $file
должныif [ -f "$file" ]
,> "$file.tmp"
иmv "$file.tmp" "$file"
, соответственно, обрабатывать имена файлов, в которых могут быть пробелы (или другие забавные символы). (Командаeval "sed …
также изменяет имена файлов, в которых есть пробелы.)*
shift
принимает необязательный аргумент: положительное целое число, указывающее, сколько параметров нужно сместить. По умолчанию один (1
). Например,shift 4
причины$5
становиться$1
,$6
становиться$2
и так далее. (Обратите внимание, что пример в Руководстве по Bash для начинающих неверен.) И поэтому ваш сценарий может быть изменен, чтобы ончто можно считать более понятным.
Конец Примечание / Предупреждение:
Язык командной строки Windows (пакетный файл) также поддерживает
SHIFT
команду, которая делает в основном то же самое, что иshift
команда в оболочках Unix, с одним поразительным отличием, которое я скрою, чтобы не допустить путаницы:источник
shift
может быть применен кwhile
,until
и дажеfor
петли для обработки массивов в гораздо более тонкими способами , чем может простойfor
цикл. Я часто нахожу это полезным вfor
таких циклах, как ...set -f -- $args; IFS=$split; for arg do set -- $arg; shift "${number_of_fields_to_discard}" && fn_that_wants_split_arg "$arg"; done
Самое простое объяснение это. Рассмотрим команду:
Без посторонней помощи
shift
вы не можете извлечь полное значение местоположения, поскольку это значение может быть произвольно длинным. Когда вы сдвигаетесь два раза, аргиSET
иlocation
удаляются так, что:Взгляните на
$@
вещь очень долго . Это означает, что он может сохранить полное местоположение в переменную,x
несмотря на имеющиеся у него пробелы и запятую. Итак, в итоге, мы вызываем,shift
а затем позже получаем значение того, что осталось от переменной$@
.ОБНОВЛЕНИЕ Я добавляю ниже очень короткий фрагмент, показывающий концепцию и полезность,
shift
без которой было бы очень и очень трудно правильно извлечь поля.Объяснение : После
shift
переменной b должна содержаться остальная часть передаваемого материала, независимо от пробелов и т. Д.[ -n "$b" ] && echo $b
Защита является такой, что мы печатаем b, только если у нее есть содержимое.источник
"$*"
"$@"
Philippines 6014
), начальные пробелы, конечные пробелы или табуляции. (5) Кстати, вы также можете делать то, что делаете здесь, в bashx="${*:3}"
.shift
командой. Возможно, вы имеете в виду тонкие различия между $ @ и $ *. Но факт все еще остается, что мой фрагмент выше может точно извлечь местоположение, независимо от того, сколько пробелов оно имеет либо позади, либо впереди, это не имеет значения. После смены местоположение будет содержать правильное местоположение.shift
трактуйте аргументы командной строки как очередь FIFO, элемент popleft при каждом вызове.источник