Проста заміна вкладок таємничо не працює


44

Це повинно бути дійсно простим, але чомусь не працює:

sed -i.bak -E 's/\t/  /' file.txt

Замість заміни символів вкладки він замінює tсимволи. Я намагався будь-який варіант цього питання, який я міг придумати, граючи з цитуванням і т. Д. Я гугл і знайшов усіх інших, використовуючи досить схожі вирази, і вони, здається, працюють на них.

Це -EОС X X. Я подумав, що цей збій може бути результатом дивної химерності OS X sed, тому я спробував це і з Ruby (без цього -i), і отримав той самий результат:

ruby -pe '$_.gsub!(/\t/,"  ")' < file.txt > file.new

Я використовую Bash 3.2.51 для OS X і iTerm, хоча я не можу побачити, як будь-який з них може бути надзвичайно актуальним. Я не встановив жодних дивних змінних середовища, хоча можу розмістити будь-які, які ви вважаєте, що можуть бути актуальними.

Що може бути не так?

UPDATE : Повинно бутия зробив деяку іншу помилку, друкарської помилкиколи я спробував версію Ruby, такЖиль вказує, що він робить роботу (і я ніколи і НЕ було йому керувати мене неправильно!). Я не впевнений, що сталося, але я майже впевнений, що це, мабуть, була моєю помилкою.


5
Можливо, вам слід спробувати замінити \tв sedоператорі на те, CTRL-V<TAB>де <TAB>знаходиться клавіша табуляції, клавіша CTRL-Vуправління та vнатиснута разом.
unxnut

якщо рубін також отримує неправильну відповідь, то це може бути ваша бібліотека regexp. (Я перевірив обидві ваші команди, і обидві замініть вкладку на 2 пробіли.) Тож, сподіваємось, якщо ви встановите Gnu sed, він також встановить правильну бібліотеку.
ctrl-alt-delor

Відповіді:


64

Синтаксис \tсимволу вкладки в sed не є стандартним. Ця втеча є розширенням sed GNU . В Інтернеті ви знайдете безліч прикладів, які використовують його, оскільки багато людей використовують GNU sed (це реалізація sed у невбудованому Linux). Але OS X sed , як і інші * BSD sed, не підтримує \tвкладку і замість цього розглядає \tяк зміст зворотної косої риси, за якою слід t.

Є багато рішень, таких як:

  • Використовуйте буквальний символ вкладки.

    sed -i.bak 's/  /  /' file.txt
    
  • Використовуйте trабо printfдля створення символу вкладки.

    sed -i.bak "s/$(printf '\t')/  /" file.txt
    sed -i.bak "s/$(echo a | tr 'a' '\t')/  /" file.txt
    
  • Використовуйте синтаксис рядка bash, що дозволяє виконувати зворотні риси .

    sed -i.bak $'s/\t/  /' file.txt
    
  • Використовуйте Perl, Python або Ruby. Фрагмент Ruby, який ви опублікували, працює.


Для sed-скриптів, які містяться в ...sedскрипті (використовується через -fопцію), для мене є єдиною можливістю букви буквальних вкладок. Редагуючи це за допомогою vim, set noexpandtabважливо.
Тобіас

Попередження. Використовуйте цю техніку "буквального символу вкладки" лише тоді, коли ви хочете, щоб ваш колега повернувся за вами і згодом зламав ваш сценарій. Використовуйте цю trтехніку лише в тому випадку, якщо ви хочете, щоб ваш колега зарізав вам обличчя, коли вони прочитали ваш сценарій.
Бруно Броноський

Чи в другому блоці коду замінено другий знак подвійного лапки? Мені довелося перенести його туди, де зараз є заключна одноцінова пропозиція.
Еллен Спертус

Дякую за посилання на синтаксис рядка bash ... Я поняття не мав (і це найкращий варіант, IMHO).
levigroker

sed $'s/<regex>/\t/' file.txtпрацює для вставки, але, $здається, зламає мій сценарій, коли я намагаюся включити частину регулярного вираження в свою заміну, тобто sed $'s,\(ontology/[0-9]\+\),\t\txxx\1xxx\t\t,'дає `xxxxxx`, коли очікуване значення збігу замінено на ``. Чи існує еквівалент, \1коли використовується синтаксис рядка bash? Редагувати: мається на увазі символ Unicode U + 231C посередині xxx <U + 231C> xxx.
Джош

14

Використовуйте специфічне котирування Bash, яке дозволяє використовувати рядки, як у C, так що справжній символ вкладки передається sed, а не послідовності втечі:

sed -i.bak -E $'s/\t/  /' file.txt

1
Також називається "ANSI-C" цитуванням, якщо інші хочуть дізнатися більше інформації про це.
wisbucky

2
Здається, працює над будь-якою оболонкою Bourne, працює також і на UNHIX-і, що не мають башти. Однак не працює на csh-варіантах.
jornane

2
sed -i $'s/\t/  /g' file.txt 

працює для мене на OS X і є тією ж командою, яку я використовую в Linux постійно.


Зауважте, що це замінює всі вкладки в кожному рядку, тоді як OP має намір замінити лише перший (судячи з команди, яку вони використовують).
Kusalananda

1

Як зазначалося, не всі sedреалізації підтримують позначення \tяк горизонтальної вкладки.

Ви можете легко досягти своєї заміни за допомогою:

 perl -pi.old -e 's{\t+}{ }g' file.txt

Це виконує заміну in situ, яка зберігає ваш вихідний файл як "* .old". Perl дозволяє чергувати роздільники для класичного, /роблячи вираз набагато зрозумілішим (тобто позбавленим синдрому "нахиленої зубочистки").

+Каже один або більше повторень символу табуляції повинні бути замінені. gМодифікатор дозволяє глобальну заміну на протязі кінці кожного рядка.


0

Ви також можете використовувати echoвсередині sed:

sed -i "s/$(echo '\t')//g"


Зауважте, що це echo '\t'буде просто виведенням \tу реалізацію деяких оболонок echo.
Kusalananda

0

Якщо ви хочете більш потужний sed(підтримуючий \tі більше), ніж той, що знаходиться в OS X, встановіть GNU sed .


Оскільки він не працював і з Ruby, я не впевнений, чому б я зробив висновок, що sedпроблема ОС X. Чи є у вас підстави вважати, що це проблема? Я був би радий встановити GNU sed, якби я мав підстави вважати, що це вирішить проблему, але, схоже, я це майже виключив.
іконоборство

З Ruby вам доведеться використовувати лише одну зворотну косу ruby -pe '$_.gsub!(/\t/," ")' < file.txt
рису

0

Якщо це нормально вимагати bashабо zshяк оболонку, то це найпростіше рішення, про яке я можу придумати:

sed "s/$(echo -n -e "\t")/ /" file.txt

Однак зауважте, що echoпрапори ( -nта -e) не визначені в POSIX, тому оболонка, відповідна POSIX, не потребує розуміння прапорців цих тез, проте багато хто з міркувань сумісності.


-1

Я здивований, що ніхто не запропонував дуже простого рішення: sed -i.bak -E 's/\\\t/ /' file.txt Це повинно зробити трюк.

Вам потрібно уникнути втечі (звідси 3 \ s), щоб sed зрозумів, що ви намагаєтесь використовувати символ \ t у регулярному виразі, коли все замінено ...


Чому конкретно три відхилення від накипу?
Майкл Гомер

3
Якщо я використовую GNU sed, одного \ достатньо, тому що не потрібно уникати. Проблема полягає в тому, що BSD sedне підтримує цей синтаксис для вкладок.
іконоборство

Не працює на моєму El Capitan.
Франклін Ю

-4

Це працювало для мене.

sed -e 's / [\ t] / / g'


3
Це тому, що ви використовуєте GNU sed. Це не те, що використовує ОП.
Kusalananda
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.