sed работает при вводе из echo, но не из файла

/ proc / self - это синтаксический сахар. Это ярлык для соединения / proc / и результата системного вызова getpid () (доступного в bash как метапеременная $$). Это может сбивать с толку, хотя в случае сценариев оболочки, поскольку многие из операторов вызывают другие процессы, в комплекте с собственными PID ... PID, которые чаще всего относятся к мертвым процессам. Учтите:

root@vps01:~# ls -l /proc/self/fd
total 0
lrwx------ 1 root root 64 Jan  1 01:51 0 -> /dev/pts/0
lrwx------ 1 root root 64 Jan  1 01:51 1 -> /dev/pts/0
lrwx------ 1 root root 64 Jan  1 01:51 2 -> /dev/pts/0
lr-x------ 1 root root 64 Jan  1 01:51 3 -> /proc/26562/fd
root@vps01:~# echo $$
593

'/ bin / ls' будет оценивать путь к каталогу, разрешая его как / proc / 26563, поскольку это PID процесса - вновь созданного процесса / bin / ls - который читает содержимое файла каталог. Но к тому времени, когда следующий процесс в конвейере, в случае сценария оболочки, или к тому времени, когда появится приглашение, в случае интерактивной оболочки путь больше не существует и вывод информации относится к несуществующему процессу.

Это применимо только к внешним командам (тем, которые являются фактическими исполняемыми программными файлами, а не встроены в саму оболочку). Таким образом, вы получите разные результаты, если, скажем, используете подстановку имен файлов для получения списка содержимого каталога, вместо того, чтобы передавать имя пути внешнему процессу / bin / ls:

root@vps01:~# ls /proc/self/fd
0  1  2  3
root@vps01:~/specs# echo /proc/self/fd/*
/proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2 /proc/self/fd/255 /proc/self/fd/3

В первой строке оболочка создала новый процесс '/ bin / ls' с помощью системного вызова exec (), передав "/ proc / self / fd" как argv [1]. '/ bin / ls', в свою очередь, открыл каталог / proc / self / fd и прочитал, а затем распечатал его содержимое при итерации по ним.

Во второй строке, однако, негласно используется glob () для расширения списка имен файлов; они передаются как массив строк для эха.(Обычно реализуется как внутренняя команда, но часто есть также двоичный файл / bin / echo ... но эта часть на самом деле не имеет значения, поскольку echo имеет дело только со строками, которые никогда не передаются никаким системным вызовам, связанным с именами путей.)

Теперь рассмотрим следующий случай:

root@vps01:~# cd /proc/self/fd
root@vps01:~# ls
0  1  2  255

Здесь оболочка, родительский процесс для / bin / ls, сделала подкаталог / proc / self своим текущим каталогом . Таким образом, относительные пути оцениваются с его точки зрения. Я предполагаю, что это связано с семантикой файла POSIX, где вы можете создать несколько жестких ссылок на файл, включая любые открытые файловые дескрипторы. Итак, на этот раз / bin / ls ведет себя аналогично echo / proc / $$ / fd / *.

1
18.01.2017, 00:41
3 ответа

Прошу прощения, но ваш пример echo не работает. Кажется, это работает, потому что двойные кавычки ( ") интерпретируются bash и никогда не передаются в sed .

Обратите внимание на разницу между следующими двумя примерами:

$ echo "john.doe@gmail.com" 
john.doe@gmail.com
$ echo "\"john.doe@gmail.com\"" 
"john.doe@gmail.com"

Ваша команда echo не передает " в sed , поэтому кажется, что она работает, потому что нет " для удаления в входная строка.

Если вы попытаетесь правильно экранировать ", пример echo не будет работать, как пример файла :

$ echo  "\"john.doe@gmail.com\"" | sed 's/"([^"]*)"/\0/g'  
"john.doe@gmail.com"

Вы ] sed имеет две ошибки:

  1. Вы используете расширенный синтаксис регулярного выражения. Вы можете использовать его, только если у вас есть gnu sed. Разница в том, как они используют круглые скобки.
  2. Вы должны считать обратные ссылки, начиная с 1 .

Итак, правильная команда:

echo  "\"john.doe@gmail.com\"" | sed 's/"\([^"]*\)"/\1/g' 

или, если ваш sed поддерживает расширенное регулярное выражение:

echo "\"john.doe@gmail.com\"" | sed -E 's/"([^"]*)"/\1/g'
9
27.01.2020, 23:11

Как упоминалось @andcoz, для этого

$ sed -i '' 's/"([^"]*)"/\0/g' ~/Desktop/emails.txt

необходимо экранировать круглые скобки и изменить обратную ссылку с \ 0 на \ 1 ].

После модификации функциональная команда sed выглядит следующим образом:

$ sed -i '' 's/"\([^"]*\)"/\1/g' ~/Desktop/emails.txt  
1
27.01.2020, 23:11
gv@debian:$ cat a.txt
"john.doe@gmail.com"

gv@debian:$ sed 's#"##g' a.txt #remove all quotes
john.doe@gmail.com

gv@debian:$ cat a.txt |tr -d '"' #remove all quotes
john.doe@gmail.com

gv@debian:$ sed 's#^"##g; s#"$##g' a.txt #remove first and last quote 
john.doe@gmail.com

gv@debian:$ a="\"john.doe@gmail.com\"";echo -e "$a" "\n" "${a: 1:-1}" #remove first and last char
"john.doe@gmail.com" 
 john.doe@gmail.com
3
27.01.2020, 23:11

Теги

Похожие вопросы