Додавання пропущених нулів на початку кожного рядка, де менше 4 знаків


1

Я б запитав вас, як вирішити цю проблему: мені потрібно поставити 0 у кожному рядку, де слово має менше 4 знаків.

Приклад вхідного файлу:

30
1
508
A0EA
A0EB
A0EC
A0ED

Бажаний вихід повинен бути:

0030
0001
0508
A0EA
A0EB
A0EC
A0ED

Заздалегідь дякую за підтримку.


1
ви можете використовувати awk+printf, див gnu.org/software/gawk/manual/html_node / ... і gnu.org/software/gawk/manual/html_node/Printf-Examples.html
Sundeep

1
@Sundeep, не найпростіший підхід, коли введення в шістнадцятковому рівні, як тут.
Стефан Шазелас

1
Чи зберігаються ці значення у файлі чи масиві оболонок або вже читаються в циклі оболонок з якоїсь іншої причини чи з чогось іншого? Це шістнадцяткові номери чи щось інше? Чи є у вас колись рядки вводу вже довші 4 символів, і якщо так, то чи слід їх якось обрізати чи залишити як є?
Ед Мортон

@ StéphaneChazelas о, я не розумів, що у awk не було способу заповнити нуль
Sundeep

Відповіді:


5

Ви можете додати 4 провідні нулі до всіх рядків, а потім отримати 4 останні символи кожного:

sed 's/^/0000/; s/^.*\(.\{4\}\)/\1/' < file

Або уникати обрізання чисел, шириною яких було більше 4 цифр:

sed 's/^/0000/; s/^.\{1,4\}\(.\{4\}\)/\1/' < file

приємно. "sed 's / ^ / 0000 /; s /^.* (. \ {4 \}) / \ 1 /' <файл" працює ідеально
Mac

3

Ще один для суміші:

$ numfmt --format='%04.0f' --invalid=ignore < file
0030
0001
0508
A0EA
A0EB
A0EC
A0ED

numfmt надається пакетом GNU Coreutils.


1

З GNU awk для strtonum (), якщо ваш вхід є шістнадцяткові числа:

$ awk '{printf "%04X\n", strtonum("0x"$0)}' file
0030
0001
0508
A0EA
A0EB
A0EC
A0ED

Якщо GNU awk незалежно від того, чи є ваш внесок шестигранним чи ні:

$ awk '{print gensub(/ /,0,"g",sprintf("%4s",$0))}' file
0030
0001
0508
A0EA
A0EB
A0EC
A0ED

З будь-яким дивом, чи є ваш внесок шістнадцятковим чи ні:

$ awk '{v=sprintf("%4s",$0); gsub(/ /,0,v); print v}' file
0030
0001
0508
A0EA
A0EB
A0EC

або навіть:

$ awk '{$0=sprintf("%4s",$0); gsub(/ /,0)} 1' file
0030
0001
0508
A0EA
A0EB
A0EC
A0ED

1
Також працює добре. Дякую
Mac

0

За допомогою zshоболонки ви можете використовувати l:length::string:прапор розширення зліва-padding.

$ var=FF
$ echo ${(l:4::0:)var}
00FF

Щоб застосувати його до кожного слова у файлі:

printf '%s\n' ${(l:4::0:)$(<file)}

Зауважте, що цей оператор також усіма словами, розмірами більше 4 символів.


0

Якщо значення вже знаходяться всередині оболонки і є всі шістнадцяткові числа:

$ set -- 30 1 508 A0EA A0EB A0EC A0ED
$ for var; do printf '%04X\n' "0x$var"; done
0030
0001
0508
A0EA
A0EB
A0EC
A0ED

Якщо значення рядка можуть бути будь-якими рядками (навіть довше 4 символів) і lineмістять значення (и) рядка, рішення стає складнішим:

[ "${#line}" -lt 4 ] && 
    printf '%0*d%s\n' "$((4-${#line}))" 0 "$line" || 
        printf '%s\n' "${line}"

буде надрукувати значення з такою кількістю нулів, скільки потрібно для створення рядка в 4 символи.

Потім для зовнішнього файлу (sed і awk рішення швидші для зовнішніх файлів) зробіть цикл і розгорніть код, щоб зробити його більш розбірливим як:

while read -r line; do
    if [ "${#line}" -lt 4 ]; then 
        printf '%0*d%s\n' "$((4-${#line}))" 0 "$line"
    else
        printf '%s\n' "${line}"
    fi
done <file

Приємна робота зі змішуванням пари функцій.
Мак

Це буде вкрай повільно, дивіться, чому "використовується-а-оболонка-петля" для обробки тексту вважається-поганою-практикою . Можливо, принаймні на порядок повільніше, ніж рішення sed або awk.
Ед Мортон

Так, Ед, це правда. Ну, але тільки для зовнішнього файлу. Якщо значення в оболонці вже знаходяться в змінній типу line, це швидше.
Ісаак

Добре, що ОП не сказав жодним чином, тому для всіх ми знаємо, що він має масив значень оболонки і пробирається через них уже з інших причин, і в цьому випадку ви не хочете називати sed або awk для кожного значення окремо. Ми повинні були задати кілька питань, перш ніж переходити до публікації відповідей - я додав коментар під цим питанням зараз.
Ед Мортон

0
$ perl -ne 'printf "%05s", $_' ip.txt
0030
0001
0508
A0EA
A0EB
A0EC
A0ED

Використовуючи 5замість 4тут, оскільки в кожному рядку також є символ нового рядка. Рядки з більш ніж 5 символами будуть надруковані як є.


0

Менш елегантний спосіб:

cat file | sed 's/^\(...\)$/0\1/' | sed 's/^\(..\)$/00\1/' | sed 's/^\(.\)$/000\1/'

1
Вам не потрібно передавати вихід sed в інший сед, принаймні, не тоді, коли ви просто робите ряд простих перетворень. Ви можете використовувати декілька -eаргументів, а можна просто використовувати крапку з двокрапкою для розділення команд sed. наприклад sed -e 's/foo/bar/' -e 's/abc/xyz'або sed -e 's/foo/bar/; s/abc/xyz/'. Вам також не потрібно cat- sed може сама читати файли.
cas


0

Це свого роду кульгавий (файли повинні бути коротшими за getconf ARG_MAXбайти), але це працює:

printf '%4s\n' $(<file) | tr ' ' 0

1
Просто використовуйте '%04s\n'і кидайте tr.
glenn jackman

0
cat file.txt | awk -vlen=4 '{
  add=""          #empty prefix to be added

  if(length($1)!=len){
       for(i=(len-length($1));i<=length($1);i++)
           add=add"0"          #add prefix as necessary
  }

  print $1""add

 }'

Не соромтеся змінювати змінну lenна свій смак.


-1

Я зробив, використовуючи if умова та awk

count_line=`awk '{print NR}' p.txt| sed -n '$p'`

for ((i=1;i<=$count_line;i++)); do j=`awk -v i="$i" -F "" 'NR==i{print NF}' p.txt`; if [[ $j == "1" ]]; then awk -v i="$i" -F "" 'NR==i{print "000"$0}' p.txt; elif [[ $j == "2" ]]; then awk -v i="$i" -F "" 'NR==i{print "00"$0}' p.txt ; elif [[ $j == "3" ]]; then awk -v i="$i" -F "" 'NR==i{print "0"$0}' p.txt; else awk -v i="$i" 'NR==i{print $0}' p.txt; fi; done

вихід

0030
0001
0508
A0EA
A0EB
A0EC
A0ED
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.