Как работает эта команда замены sed с большим количеством знаков @?

8

Кто-нибудь может объяснить, как sedработает эта команда?

sed 's@+@ @g;s@%@\\x@g' | xargs -0 printf "%b"
Радж
источник
3
Обычный способ сделать это - использовать косые черты, но это может стать громоздким, если вы ищете и заменяете что-то косыми чертами. Это не тот случай, поэтому, хотя он и прекрасно, он сбивает с толку будущих сопровождающих, таких как вы.
Торбьерн Равн Андерсен
2
... и заставляет их узнавать что-то новое об sedэтом пути! :)
десерт

Ответы:

15

В sed команды замены обычно записываются как s/pattern/replacement/options. Тем не менее, это не обязательно использовать /- вы можете использовать другие символы, если это удобно, так что это может быть s@pattern@replacement@optionsили s:foo:bar:g. s@+@ @gэто как s/+/ /g- заменить все +пробелы. Аналогичным образом s@%@\\x@gзаменяет все %на \x(одна обратная косая черта является escape-символом в sed, поэтому для получения реальной обратной косой черты нужно два).

Строка как foo+%2Fbarтогда станет foo \x2Fbar. printf "%b"развернет последовательности, экранированные обратной косой чертой, например \x2F(символ ASCII, шестнадцатеричное значение которого равно 2F /), чтобы, наконец, дать вам foo /bar.

Мур
источник
2
Вкратце, URL-> декодер имени файла.
Торбьерн Равн Андерсен
10

Команда, которую вы запрашиваете для декодирования +es и %sequence из URL, это не просто sedкоманда, это конвейер, который обрабатывает ввод sed, а затем передает его xargsдля дальнейшей обработки. Сначала давайте посмотрим на sedкоманду:

sed 's@+@ @g;s@%@\\x@g'

Возможно, вы более привыкли видеть его с разделителем, /а не @в качестве разделителя, что легко можно было бы сделать здесь без осложнений, поскольку оно не /встречается ни в шаблонах поиска, ни в текстах замены. Эта команда эквивалентна:

sed 's/+/ /g;s/%/\\x/g'

Мол /, @это очень хороший знак пунктуации для sed.

На каждой строке ввода:

  1. s@+@ @g( s/+/ /g) подставляет ( s) вхождения +с пробелом. Это влияет на все +es в строке ( g), а не только на первый.

  2. ; завершает действие («команда») и позволяет вам указать другое в том же «сценарии».

  3. s@%@\\x@g( s/%/\\x/g) подстановки ( s) вхождения %с \x. Как и прежде, он действует на все, а не только на первую строку каждой строки ( g).

    В представляет только один , потому что имеет особое значение для . Его особое значение на самом деле заключается в том, что вы используете символ, чтобы убрать особое значение другого символа, который следует за ним, который в противном случае имел бы особое значение. Так что надо сбежать как .\\x\\\\sed\\


Теперь давайте посмотрим на xargsкоманду, целью которой является запуск printf.

xargsстроит командные строки. Если вы запускаете , где находится одно или несколько слов, запускается с дополнительными аргументами командной строки, считанными из его ввода. В этом случае входные данные являются выходными данными из-за pipe ( ). Обычно интерпретирует любой пробел в своем входном значении, чтобы обозначить, что текст до и после него представляет собой отдельные аргументы, но опция заставляет вместо этого разделять аргументы при появлении нулевого символа .xargs command...command...xargscommand...xargssed|xargs-0

При предполагаемом использовании вашей команды нулевой символ не будет отображаться и xargsбудет выполняться printf %bтолько с одним дополнительным аргументом командной строки, выводом sedкоманды. Таким образом, хотя в общем случае это не эквивалентно, в этом случае весь конвейер мог бы быть написан так, используя подстановку команд вместо xargs:

printf '%b\n' "$(sed 's/+/ /g;s/%/\\x/g')"

Что же касается того, что printfпредполагается сделать здесь, в Муре говорит о %bформате спецификатор потребляет и печатает аргумент (например %s) , но вызывает обратный слеш - от сортировки по sedкоманде на левой стороне трубы была написано для создания - быть переведено в символы, которые они представляют .

Предположим, я запускаю эту команду и передаю в http://foldoc.org/debugging%20by%20printfкачестве ввода. Я получаю в http://foldoc.org/debugging by printfкачестве вывода, потому что %20последовательности переводятся в пробелы.

Элия ​​Каган
источник
3

Это красота sed, она применяет свои парадигмы к себе ... После команды (например, sили , trили ничего), то следующий символ считается разделителем.

Вы должны сделать правильный выбор, чтобы избежать вмешательства в оболочку и саму команду, и сохранить ее читабельной, но совершенно правильно написать что-то столь ужасное, как:

echo 'arrival' | sed srarbrg

... и получить brrivblв результате, что вы ожидаете. Вы можете весело провести время, сделав это действительно загадочным, например:

echo 'arrival' | sed s\fa\fb\fg   # \f is form feed, chr(12)

Обычное использование - использовать косую черту в качестве разделителя, но когда ваше выражение содержит разделитель, вам будет проще понять, что это за цель. Ваш разделитель может быть любым в диапазоне ASCII8 (многобайтовые разделители, например, £вызывают ошибку).

Просто помните, что цель состоит в том, чтобы сделать вещи проще, а не более загадочными.

Marabiloso
источник
Работая с загадочной идеей, это действительная команда sed, хотя она не делает ничего полезного:sed "snack is an apple or something" <<< "I sed your snack is an apple or something"
wjandrea
Ницца! Да, вы тоже можете использовать sedкоманды в качестве тизеров мозга, насколько это отвратительно?
Марабилосо