I'm trying to convert "Hello" to 48 65 6c 6c 6f
in hexadecimal as efficiently as possible usi开发者_Go百科ng the command line.
I've tried looking at printf
and google, but I can't get anywhere.
Any help greatly appreciated.
Many thanks in advance,
echo -n "Hello" | od -A n -t x1
Explanation:
- The
echo
program will provide the string to the next command. - The
-n
flag tells echo to not generate a new line at the end of the "Hello". - The
od
program is the "octal dump" program. (We will be providing a flag to tell it to dump it in hexadecimal instead of octal.) - The
-A n
flag is short for--address-radix=n
, with n being short for "none". Without this part, the command would output an ugly numerical address prefix on the left side. This is useful for large dumps, but for a short string it is unnecessary. - The
-t x1
flag is short for--format=x1
, with the x being short for "hexadecimal" and the 1 meaning 1 byte.
If you want to do this and remove the spaces you need:
echo -n "Hello" | od -A n -t x1 | sed 's/ *//g'
The first two commands in the pipeline are well explained by @TMS in his answer, as edited by @James. The last command differs from @TMS comment in that it is both correct and has been tested. The explanation is:
sed
is a stream editor.s
is the substitute command./
opens a regular expression - any character may be used./
is conventional, but inconvenient for processing, say, XML or path names./
or the alternate character you chose, closes the regular expression and opens the substitution string.- In
/ */
the*
matches any sequence of the previous character (in this case, a space). /
or the alternate character you chose, closes the substitution string. In this case, the substitution string//
is empty, i.e. the match is deleted.g
is the option to do this substitution globally on each line instead of just once for each line.- The quotes keep the command parser from getting confused - the whole
sequence is passed to
sed
as the first option, namely, ased
script.
@TMS brain child (sed 's/^ *//'
) only strips spaces from the beginning of each line (^
matches the beginning of the line - 'pattern space' in sed
-speak).
If you additionally want to remove newlines, the easiest way is to append
| tr -d '\n'
to the command pipes. It functions as follows:
|
feeds the previously processed stream to this command's standard input.tr
is the translate command.-d
specifies deleting the match characters.- Quotes list your match characters - in this case just newline (
\n
). Translate only matches single characters, not sequences.
sed
is uniquely retarded when dealing with newlines. This is because sed
is one of the oldest unix
commands - it was created before people really knew what they were doing. Pervasive legacy software keeps it from being fixed. I know this because I was born before unix
was born.
The historical origin of the problem was the idea that a newline was a line separator, not part of the line. It was therefore stripped by line processing utilities and reinserted by output utilities. The trouble is, this makes assumptions about the structure of user data and imposes unnatural restrictions in many settings. sed
's inability to easily remove newlines is one of the most common examples of that malformed ideology causing grief.
It is possible to remove newlines with sed
- it is just that all solutions I know about make sed
process the whole file at once, which chokes for very large files, defeating the purpose of a stream editor. Any solution that retains line processing, if it is possible, would be an unreadable rat's nest of multiple pipes.
If you insist on using sed
try:
sed -z 's/\n//g'
-z
tells sed
to use nulls as line separators.
Internally, a string in C
is terminated with a null. The -z
option is also a result of legacy, provided as a convenience for C
programmers who might like to use a temporary file filled with C
-strings and uncluttered by newlines. They can then easily read and process one string at a time. Again, the early assumptions about use cases impose artificial restrictions on user data.
If you omit the g
option, this command removes only the first newline. With the -z
option sed
interprets the entire file as one line (unless there are stray nulls embedded in the file), terminated by a null and so this also chokes on large files.
You might think
sed 's/^/\x00/' | sed -z 's/\n//' | sed 's/\x00//'
might work. The first command puts a null at the front of each line on a line by line basis, resulting in \n\x00
ending every line. The second command removes one newline from each line, now delimited by nulls - there will be only one newline by virtue of the first command. All that is left are the spurious nulls. So far so good. The broken idea here is that the pipe will feed the last command on a line by line basis, since that is how the stream was built. Actually, the last command, as written, will only remove one null since now the entire file has no newlines and is therefore one line.
Simple pipe implementation uses an intermediate temporary file and all input is processed and fed to the file. The next command may be running in another thread, concurrently reading that file, but it just sees the stream as a whole (albeit incomplete) and has no awareness of the chunk boundaries feeding the file. Even if the pipe is a memory buffer, the next command sees the stream as a whole. The defect is inextricably baked into sed
.
To make this approach work, you need a g
option on the last command, so again, it chokes on large files.
The bottom line is this: don't use sed
to process newlines.
echo hello | hexdump -v -e '/1 "%02X "'
Playing around with this further, A working solution is to remove the "*", it is unnecessary for both the original requirement to simply remove spaces as well if substituting an actual character is desired, as follows
echo -n "Hello" | od -A n -t x1 | sed 's/ /%/g'
%48%65%6c%6c%6f
So, I consider this as an improvement answering the original Q since the statement now does exactly what is required, not just apparently.
Combining the answers from TMS and i-always-rtfm-and-stfw, the following works under Windows using gnu-utils versions of the programs 'od', 'sed', and 'tr':
echo "Hello"| tr -d '\42' | tr -d '\n' | tr -d '\r' | od -v -A n -tx1 | sed "s/ //g"
or in a CMD file as:
@echo "%1"| tr -d '\42' | tr -d '\n' | tr -d '\r' | od -v -A n -tx1 | sed "s/ //g"
A limitation on my solution is it will remove all double quotes (").
"tr -d '\42'" removes quote marks that the Windows 'echo' will include.
"tr -d '\r'" removes the carriage return, which Windows includes as well as '\n'.
The pipe (|) character must follow immediately after the string or the Windows echo will add that space after the string.
There is no '-n' switch to the Windows echo command.
精彩评论