sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Bu sed
betiğin tab
her satırın önüne bir eklemesini bekliyorum , $filename
ancak öyle değil. Bazı nedenlerden dolayı onun t
yerine a ekliyor.
sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Bu sed
betiğin tab
her satırın önüne bir eklemesini bekliyorum , $filename
ancak öyle değil. Bazı nedenlerden dolayı onun t
yerine a ekliyor.
Yanıtlar:
Tüm sed
anlayış sürümleri değil \t
. Bunun yerine hazır bilgi sekmesi eklemeniz yeterlidir ( Ctrl- Vardından - tuşuna basın Tab).
\t
ifade yedek parçası (tanınan \t
gayet desen eşleştirme kısmen)
Bash'i kullanarak programlı olarak bir SEKME karakteri ekleyebilirsiniz:
TAB=$'\t'
echo 'line' | sed "s/.*/${TAB}&/g"
echo 'line' | sed 's/.*/'"${TAB}"'&/g' # use of Bash string concatenation
$'string'
ama eksikliği açıklama. Aslında, son derece garip kullanım nedeniyle muhtemelen eksik bir anlayışa sahip olduğunuzdan şüpheleniyorum (çoğumuz bash ile yaptığımız gibi). Aşağıdaki açıklamama bakın: stackoverflow.com/a/43190120/117471
$TAB
tek tırnak içindeki gibi değişkenleri genişletmeyeceğini unutmayın , bu nedenle çift tırnak kullanmanız gerekecek.
*
Çift tırnak içinde kullanmaya dikkat edin ... bu, amaçladığınız normal ifade olarak değil, bir küre olarak değerlendirilecektir.
@sedit doğru yoldaydı, ancak bir değişkeni tanımlamak biraz garip.
Bunu bash'ta yapmanın yolu, tek tırnaklı dizenizin önüne bir dolar işareti koymaktır.
$ echo -e '1\n2\n3'
1
2
3
$ echo -e '1\n2\n3' | sed 's/.*/\t&/g'
t1
t2
t3
$ echo -e '1\n2\n3' | sed $'s/.*/\t&/g'
1
2
3
Dizenizin değişken genişletme içermesi gerekiyorsa, tırnak içine alınmış dizeleri şu şekilde bir araya getirebilirsiniz:
$ timestamp=$(date +%s)
$ echo -e '1\n2\n3' | sed "s/.*/$timestamp"$'\t&/g'
1491237958 1
1491237958 2
1491237958 3
Bash'de $'string'
"ANSI-C genişlemesine" neden olur. Ve bu gibi şeyler kullandığınızda çoğumuz ne bekliyordunuz \t
, \r
, \n
: Dan vb https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quoting
$ 'Dizge' biçimindeki sözcükler özel olarak ele alınır. Sözcük , ANSI C standardında belirtildiği gibi ters eğik çizgi kaçış karakterleri değiştirilerek dizeye genişler . Varsa ters eğik çizgi kaçış dizilerinin kodu çözülür ...
Genişletilmiş sonuç sanki dolar işareti yokmuş gibi tek tırnaklıdır.
Şahsen, bash'ı önlemek için gösterilen çabaların çoğunun aptalca olduğunu düşünüyorum çünkü bashizmlerden kaçınmak kodunuzu taşınabilir hale getirmez *. (Kodunuz, bash'dan bash -eu
kaçınmaya ve sh
[mutlak bir POSIX ninja değilseniz] kullanmaya çalıştığınızda olduğundan daha az kırılgan olacaktır .) Ancak bununla ilgili dini bir argüman yerine, size EN İYİSİNİ vereceğim * Cevap.
$ echo -e '1\n2\n3' | sed "s/.*/$(printf '\t')&/g"
1
2
3
* En iyi cevap? Evet, çünkü çoğu anti-bash kabuk betikleyicisinin kodlarında yanlış yapacaklarına bir örnek @ robrecord'un cevabındakiecho '\t'
gibi kullanmaktır . Bu GNU yankısı için çalışacak, ancak BSD yankısı için çalışmayacaktır. Bu, Açık Grup tarafından http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 adresinde açıklanmaktadır Ve bu, bashizmlerden kaçınmaya çalışmanın neden genellikle başarısız olduğunun bir örneğidir.
Ubuntu 12.04'te (LTS) bir Bash kabuğu ile buna benzer bir şey kullandım:
İle yeni bir satır eklemek için sekme, ikinci zaman ilk eşleştirilir:
sed -i '/first/a \\t second' filename
Değiştirmek için ilk olan sekme saniyede :
sed -i 's/first/\\t second/g' filename
\\t
ve kullanmayın \t
.
Kullanın $(echo '\t')
. Modelin etrafında alıntılara ihtiyacınız olacak.
Örneğin. Bir sekmeyi kaldırmak için:
sed "s/$(echo '\t')//"
echo '\t'
ile 2 ayrı karakter çıkacaktır. POSIX taşınabilir yolu kullanmaktır printf '\t'
. Bu yüzden şunu söylüyorum: Bash kullanmayarak kodunuzu taşınabilir hale getirmeye çalışmayın. Düşündüğünden daha zor. Kullanmak bash
, çoğumuzun yapabileceği en taşınabilir şeydir.
sed
Gerçekte, sadece satırın önüne bir sekme eklemek istediğinizde, bir değişiklik yapmak için kullanmanıza gerek yoktur. Bu durum için ikame, özellikle büyük dosyalarla çalışırken, yalnızca yazdırmaya kıyasla pahalı bir işlemdir. Normal ifade olmadığı için okunması daha kolaydır.
örneğin awk kullanarak
awk '{print "\t"$0}' $filename > temp && mv temp $filename
Bunu Mac'te kullandım:
sed -i '' $'$i\\\n\\\thello\n' filename
sed
desteklemiyor \t
veya \n
bunun gibi başka kaçış dizileri . Bunu yapmanın tek yolu, kullanarak komut dosyasına sekme karakterini eklemekti sed
.
Bununla birlikte, Perl veya Python kullanmayı düşünebilirsiniz. İşte tüm akış düzenli ifadeleri için kullandığım yazdığım kısa bir Python betiği:
#!/usr/bin/env python
import sys
import re
def main(args):
if len(args) < 2:
print >> sys.stderr, 'Usage: <search-pattern> <replace-expr>'
raise SystemExit
p = re.compile(args[0], re.MULTILINE | re.DOTALL)
s = sys.stdin.read()
print p.sub(args[1], s),
if __name__ == '__main__':
main(sys.argv[1:])
BSD sed yerine perl kullanıyorum:
ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g"
hi
Diğerleri diğer yaklaşımlar (için yeterince bu açıklık düşünüyorum sed
, AWK
vs.). Bununla birlikte, benim özel bash
cevaplar (macOS High Sierra ve CentOS 6 / 7'de test edilmiştir) bunu takip eder.
1) OP, başlangıçta önerdiklerine benzer bir ara ve değiştir yöntemi kullanmak isterse perl
, bunun için aşağıdaki şekilde kullanılmasını öneririm . Notlar: Düzenli ifade için parantezlerin önündeki ters eğik çizgiler gerekli olmamalıdır ve bu kod satırı , ikame operatöründen (örneğin Perl 5 dokümantasyonu uyarınca ) $1
kullanımının nasıl daha iyi olduğunu gösterir .\1
perl
perl -pe 's/(.*)/\t$1/' $filename > $sedTmpFile && mv $sedTmpFile $filename
2) Bununla birlikte, ghostdog74 tarafından belirtildiği gibi , istenen işlem aslında tmp dosyasını giriş / hedef dosyasına ( ) değiştirmeden önce her satırın başına basitçe bir sekme eklemek olduğundan, tekrar $filename
tavsiye ederim, perl
ancak aşağıdaki değişiklik ile (ler):
perl -pe 's/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
## OR
perl -pe $'s/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
3) Elbette, tmp dosyası gereksizdir , bu nedenle her şeyi 'yerinde' yapmak ( -i
bayrak ekleyerek ) ve işleri daha zarif bir tek satıra basitleştirmek daha iyidir.
perl -i -pe $'s/^/\t/' $filename