LINUX.ORG.RU

Удаление переводов строк в $(..)

 ,


0

1

Только недавно узнал, что $(..) удаляет _все_ конечные/trailing «\n». Значит, если (вдруг) filename оканчивает на «\n» - уже без жестких костылей не обработать.

Как например получить realpath или dirname (возможно файл и в /..)?

Верните веру в человечество, на чем надежнее писать скрипты, python?

> file=$'a\n'
> touch "$file"
> ls "$file" | cat
> a

> realpath "$file"
/tmp/a
 
> ls "$(realpath "$file")"
/bin/ls: cannot access /tmp/a: No such file or directory


Последнее исправление: zora (всего исправлений: 5)

Ответ на: комментарий от anonymous

И не поспоришь. А posix-sh, или есть стандарты получше?

zora
() автор топика

Тикль уже предлагали?

olibjerd ★★★★★
()
Ответ на: комментарий от ziemin

Кавычками

Боюсь, вы _не проверили_. BTW кавычки при var=$(..) ничего не меняют в bash / bash-sh / dash / zsh / heirloom-sh.

zora
() автор топика
Ответ на: комментарий от ziemin

результат выполнения

Чего? filename, оканчивающийся на «\n»? Причем тут ваше echo-то?

Боюсь

Продолжайте дальше.

zora
() автор топика
Ответ на: комментарий от RiD

Ну вот, раз «товарищу» выше доступнее echo:

bash -c 'echo "$(echo -e "a\n\n")"' - херятся последние переводы строк, в случае с $(realpath «$filename») - уже неприятно.

zora
() автор топика
Ответ на: комментарий от anonymous

_filename_

Тот, что подразумевался в теме, вестимо: оканчивающийся на \n.

Причём $() к имени файла?

Удаляет _все_ (а только один) перевод строк.

zora
() автор топика

Значит, если (вдруг) filename оканчивает на «\n» - уже без жестких костылей не обработать.

Если на время забыть о тех, кто ставит переносы строк посреди имени файла, зачем тебе сабшелл?

RiD

zsh

Это в котором половина (если не больше) моих баш-скриптов не будет работать?

Deleted
()
Ответ на: комментарий от Deleted

Если на время забыть о тех,

Само собой, что так не надо делать, поэтом "(вдруг)" - в теме.

зачем тебе сабшелл?

А что ты предлагаешь realpath использовать только для вывода? Как мне его в команду передать / сохранить в переменную?

zora
() автор топика
Ответ на: комментарий от Deleted

Это в котором

Первая версия темы и мой коммент к этому посту.

zora
() автор топика
Ответ на: комментарий от zora

Обычно когда надо работать с файлами, в именах которых спецсимволы, делают так

find -print0 | xargs -0 …
Или, если надо какой-то объёмный кусок кода выполнить, то
while read -d $'\0' varname; do
    …
done < <(find -print0)
Можно через пайп передавать на while, а не через fd, но там ЕМНИП надо ещё IFS менять, можно внутри while создать локальную функцию и через parallel выполнять её, получится а-ля xargs. Если это один файл, то и заморачиваться с ним не надо, $" прекрасно работает. А ещё у тебя походу кривой баш.
┎ ~
┖ .15 at home $ mkdir test
┎ ~
┖ .15 at home $ cd test
┎ ~/test
┖ .15 at home $ tfname=$'nl\n'
┎ ~/test
┖ .14 at home $ touch a z "$tfname"
┎ ~/test
┖ .14 at home $ ls -la
total 8
drwxr-xr-x  2 fargred fargred 4096 июня  30 19:51 .
drwxr-xr-x 84 fargred fargred 4096 июня  30 19:50 ..
-rw-r--r--  1 fargred fargred    0 июня  30 19:51 a
-rw-r--r--  1 fargred fargred    0 июня  30 19:51 nl?
-rw-r--r--  1 fargred fargred    0 июня  30 19:51 z
┎ ~/test
┖ .14 at home $ echo "$(ls)"
a
nl

z

Deleted
()
Ответ на: комментарий от Deleted

В курсе, спасибо:

уже без жестких костылей не обработать

Но все равно не очень, тогда можно сразу на tcl/python/(да хоть perl):

find -print0 | xargs -0

gnu-измы

read -d
<(find -print0)

башизмы, а я на dash привык

Для объемного куска (как понимаю куска кода) можно отдельный скрипт и find -printf '%p\0' script '{}' +

zora
() автор топика
Ответ на: комментарий от Deleted

А ещё у тебя походу кривой баш.

Там zsh, то баш также выведет. Ибо тебя должно было смутить, что _есть еще символы после_ nl?, $(..) херит _последние_ - раз пять ведь это уточнил.

zora
() автор топика
Ответ на: комментарий от zora

Вопрос, надо признать, интересный. Ответ пока в голову не пришел. Думаю как-то можно переопределить поведение баша в таких случаях, т.е. man bash, но это уже завтра, на свежую голову.

RiD
()
Ответ на: комментарий от zora

gnu-измы
башизмы

Ну так ты определись, хочешь ты скрипты писать или сидеть в dash и своей проперженной BSD или Дебиане.

Для объемного куска (как понимаю куска кода) можно отдельный скрипт и find -printf '%p\0' script '{}' +

Вызывать шелл два раза? Если в скрипте будет тупо перебор файлов через while и \0, то это ж медленно, а для распоточки в баше так и так потребуется какая-то сторонная утилита, пока там множественные копроцессы до ума не довели, так что если можно вызвать её сразу, без лишних сабшеллов и «ехал интерпретатор через интерпретатор», то всяко лучше обойтись без них.

Deleted
()
Ответ на: комментарий от zora

У меня не херит

┎ ~/test
┖ .16 at home $ tfname=$'nl\nnnll'; touch "$tfname"; echo "$(ls)"
a
nl

nl
nnll
z
┎ ~/test
┖ .16 at home $ ls -la
total 8
drwxr-xr-x  2 fargred fargred 4096 июня  30 20:21 .
drwxr-xr-x 84 fargred fargred 4096 июня  30 19:50 ..
-rw-r--r--  1 fargred fargred    0 июня  30 19:51 a
-rw-r--r--  1 fargred fargred    0 июня  30 19:51 nl?
-rw-r--r--  1 fargred fargred    0 июня  30 20:21 nl?nnll
-rw-r--r--  1 fargred fargred    0 июня  30 19:51 z

Deleted
()
Ответ на: комментарий от RiD

Ответ пока в голову не пришел.

Очевидно же:

удаляет _все_ «\n» в конце - misfeature

уже без жестких костылей не обработать

Ну вопрос то не в конкретном примере, а в «надежных скриптах».

Так-то: tmp=$(realpath "$file"); realfile="${tmp%/*}/${file#*/}"

anonymous
()
Ответ на: комментарий от Deleted

У меня не херит

Ну блин (с трудом сдерживаюсь %): оставь только первые два файла, или точно также как в теме и удиви меня.

zora
() автор топика
Ответ на: комментарий от Deleted

Не тужься так, толстячок, man bash:

Command Substitution
...
Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.

anonymous
()

file=$'a\n'

Что ты этим пытался сделать?

ls «$(realpath »$file")"

А этим ты что пытался сделать?

$ cd ~/tmp/delme
$ FILE="a"
$ touch "$FILE"
$ realpath "$FILE"
/home/kroz/tmp/delme/a
$ ls $(realpath "$FILE")
/home/kroz/tmp/delme/a
Kroz ★★★★★
()
Ответ на: комментарий от Deleted

Ну так ты определись, хочешь ты скрипты писать или сидеть в dash и своей проперженной BSD или Дебиане.

У меня вообще-то арч, но по-моему ты просто фрустрируешь по поводу баша %). Если без башизмов будет не обойтись - уже задумаюсь - может стоит взять python.

Вызывать шелл два раза?

2 это же очень много, ну я так понял раз find / xargs - случай множественной обработки, а тут find .. + - вполне уместен. А если один файл - то ${ # } ${ % } - уж лучше ваших башизмом.

По-моему ты уже в неконструктив ударяешься.

zora
() автор топика
Ответ на: комментарий от Kroz

Мы говорим о файлах, которые заканчиваются на спец. символы и только на них. С файлами вида test\n\n\ntest проблем нет.

RiD
()
Ответ на: комментарий от Kroz

Что ты этим пытался сделать?

Внезапно, читаем тему:

Значит, если (вдруг) filename оканчивает на «\n»

А этим ты что пытался сделать?

Тоже внезапно:

Как например получить realpath

Резюмирую: очевидно пытался показать, что:

уже без жестких костылей не обработать

// Позволю себе заметить, что мой ответ в большинстве своем состоит из цитирования темы, что не сильно говорит в вашу пользу.

zora
() автор топика
Ответ на: комментарий от Kroz

Что говорит не в вашу пользу...

Задело что ли? Не ну просто вроде доступно написано, сейчас чуть поправил.

zora
() автор топика
Ответ на: комментарий от zora

Один вариант предложил анонимус: попробовал - работает. Базируется на отдельной обработке имени файла и пути.

Вот второй вариант:

$ FILE=$'a\n'
$ echo "$FILE"
a

$ touch "$FILE"
$ ls
a?
$ FILE2=`echo "$FILE"; echo "X"`
$ ls "${FILE2:0:(-2)}"
a?
Базируется на том, что, да, $(...) обрезает последние \n, но не те, которые в середине. Соответственно, cначала добавляем 'X' (впринципе, любой символ) а потом его убираем.

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

Базируется на том, что, да, $(...) обрезает последние \n, но не те, которые в середине.

Да, в курсе еще вроде в advanced(?)-bash-scripting видел этот «прием». Но, на мой вкус, это уже близко к жестким костылям.

Да и собственно, где нашел этот подводный камень http://www.etalabs.net/sh_tricks.html («Getting non-clobbered output from command substitution») тоже был вариант.

Но вопрос-то столько еще таких вещей (тот же echo не очень приятен): либо завязываться на конкретную реализацию, но при переносе можно сильно обжечься. И на чем писать «понадежнее», вот у меня пока dash.

В идеале хотелось бы видеть минимальный стандарт без багов: исправленный posix-sh.

zora
() автор топика
Ответ на: комментарий от zora

Но вопрос-то столько еще таких вещей (тот же echo не очень приятен): либо завязываться на конкретную реализацию, но при переносе можно сильно обжечься. И на чем писать «понадежнее», вот у меня пока dash.

ИМХО, нужно:
а) четко понимать где будет применяться (и это должно быть частью ТЗ);
б) держать баланс.

Например:
а) я знаю что скрипты, которые я для себя пишу, буду использоваться только в Linux; в худшем случае я сменю дистр, но там будет тот же bash.
Один раз мне понадобилось сделать что-то в windows - поставил cygwin. Это исключение, и я не собираюсь на него ориентироваться в своей работе.
б) Я везде пишу #!/bin/sh, хотя пользуюсь bash. Где-то встречал дистр, в котором #!/bin/bash не прокатило (а может то был Solaris, не помню). В любом случае, кросплатформенности мне добавило, в ничего взамен не потребовало - баланс хороший.

Если тебе нужна какая-то platform-specific фича - используй. Если не очень нужна - обойди стороной.

Если ты столкнулся с нюансом - найди решение. Если нет - не нужно откапывать такие вот нюансы. Проблема - это когда сталкиваешься с чем-то часто. Иначе это не проблема.

Ну, и т. п.

В идеале хотелось бы видеть минимальный стандарт без багов: исправленный posix-sh.

Моя рекомендация: posix-sh -> /bin/sh

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

а) четко понимать где будет применяться (и это должно быть частью ТЗ)

Само собой. Просто диссонанс из-за таких вот деталей, когда оказывается, что портабельный sh - как подгонка под, извиняюсь, ie6. Надо умерить идеализм.

Если тебе нужна какая-то platform-specific фича - используй.

Разумно, но с другой стороны хотелось бы стандарт на эту фичу.

Если нет - не нужно откапывать такие вот нюансы.

Ну с echo, допустим, столкнулся. Но про \n: старался писать скрипты более надежно, осознавать, что в такой простом случае отваливается - неприятно. Такой «нюанс» хотелось бы знать заранее.

а) я знаю что скрипты, которые я для себя пишу .. тот же bash.
б) Я везде пишу #!/bin/sh, хотя пользуюсь bash.

Допустим, переход на ubuntu: придется либо проверять все «echo», либо менять shebang. Или писалось, имея ввиду непортабельность -e/-n?

Моя рекомендация: posix-sh -> /bin/sh

В посикс со всеми его багами меня привлекает что это _стандарт_, есть спеки. А sh какой: bash sh-mode / dash / bourne shell?

zora
() автор топика
Ответ на: комментарий от zora

непортабельность -e/-n

Ой, с "-n" в bash <-> dash - все нормально.

zora
() автор топика
Ответ на: комментарий от zora

В посикс со всеми его багами меня привлекает что это _стандарт_, есть спеки

Важно где он применяется. Посикс, может, стандарт де-юре, но де-факто везде стоит bash/sh.

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

но де-факто везде стоит bash/sh

Де-факто везде стоял aix/ultrix/sco/hpux/.. как говорят с проблемами портирования (прибивали на поставщика) между ними.

Де-факто везде powershell.

...

Де-факто в мире «неофашизм».

Ладно, с этим уже перебор.. Ну вот чувстую, что bash - не то. Должен ли я поддерживать то, что считают неправильным?

zora
() автор топика
Ответ на: комментарий от zora

Должен ли я поддерживать то, что считают неправильным?

Это зависти от того, живешь ли ты в правильном мире, или в том, который есть.

ИМХО, «правильно» - это то, к чему нужно стремиться, то, чему нужно следовать, демонстрировать примером. Но на это никогда нельзя опираться, когда принимаешь какое-либо решение и есть внешний фактор: ОС, клиент, начальник, софт сделанный не тобой, что-то в будущем - нельзя рассчитывать то там все правильно; в таких случаях нужно смотреть на то, как есть на самом деле.

Де-факто везде powershell.

Если ты скрипты чаще запускаешь на powershell, то ессно, изучай powershell, и сдался тебе этот Posix! Я скрипты в 99.5% использую на Линукс с bash, поэтому у меня везде #!/bin/sh, и posix мне интеерсен только с точки зрения «Эх, да, bash не по стандарту, too bad», и дальше продолжить изучать ABS guide.

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

Должен ли я поддерживать то, что считают неправильным?

Это зависти от того, живешь ли ты в правильном мире, или в том, который есть.

Этот аргумент никак не могу принять. Разве что с поправкой: «имеет смысл придерживаться своего в _принципиальных_ случаях». Ладно, это уже ценности обсуждаются, откровенно на эту тему говорить сложно.

«Эх, да, bash не по стандарту, too bad», и дальше продолжить изучать ABS guide.

Меня смущает, что если бы у всех был такой подход, сидели бы до сих пор в проприетарном окружении.

Ну и раз > bash/sh

То какой смысл тогда писать #!/bin/sh?) Честнее отладил в /bin/sh (как линк на /bin/bash) -> написал #!/bin/bash + коммент вроде: tested with bash sh-mode.

anonymous
()
Ответ на: комментарий от anonymous

То какой смысл тогда писать #!/bin/sh?)

Простая замена bash на sh кушать не просит.

Честнее отладил в /bin/sh (как линк на /bin/bash) -> написал #!/bin/bash + коммент вроде: tested with bash sh-mode.- это то, к чему нужно стремиться, то, чему нужно следовать, демонстрировать примером.

Не вижу здесь чего-то, чему нужно следовать.

Честнее отладил в /bin/sh (как линк на /bin/bash) -> написал #!/bin/bash + коммент вроде: tested with bash sh-mode

Зачем? Профита не вижу, (лишние) телодвижения вижу.

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

Не вижу здесь чего-то, чему нужно следовать.
Зачем? Профита не вижу, (лишние) телодвижения вижу.

Просто ранее был пример, оставшийся без ответа:

Допустим, переход на ubuntu (у него, емнип sh - dash, или дебиан): придется либо проверять все «echo», либо менять shebang. Или писалось, имея ввиду непортабельность -e?

anonymous
()
Ответ на: комментарий от Kroz

Честнее отладил в /bin/sh (как линк на /bin/bash) .. то, чему нужно следовать, демонстрировать примером.

Не вижу здесь чего-то, чему нужно следовать.

Что-то не то цитируте).

anonymous
()
Ответ на: комментарий от zora

или точно также как в теме и удиви меня.

Ну ок, в конце правда херит. Остаётся только find, хотя он с самого начала был единственным разумным выбором.

Если без башизмов будет не обойтись - уже задумаюсь - может стоит взять python.

Бери лисп, чоужтам. Дениска всё обещал его в качестве интерпретатора командной строки, но так и не доделал.

тут find .. + - вполне уместен.

Ты не понял. Речь была не про find, а про то, куда отправляется его выхлоп.

Deleted
()
Ответ на: комментарий от Deleted

хотя он с самого начала был единственным разумным выбором

А мне это больше нравится: Удаление переводов строк в $(..) (комментарий) или Удаление переводов строк в $(..) (комментарий) (только ${FILE2:0:(-2)} -> ${FILE%X} ).

куда отправляется его выхлоп

Не-не-не, пока башизмы не убедительны: вот здесь еще ладно).

Бери лисп, чоужтам.

А мне говорили, что там часто используются ф-ии, специфичные реализации sb-...

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.