In an interactive bash terminal how do I enter a tab character? For example, if I wanted to use sed to replace "_" with tabs I'd like to use:
echo $string | sed 's/[_]/TAB/g'
Where TAB means the tab key. This works in a shell script not interactively where when I hit the tab key I get no character and a clank noise sounds. I've also tried \t but it only places t's in the string and not tabs.
Note this is mac osx.
Precede it with Control + V, followed by Tab to suppress the usual expansion behavior.
Since this question is tagged "bash"... using the "ANSI-C quoting" feature of the Bash shell is probably preferable. It expands ANSI C-style escape sequences such as \t and \n and returns the result as a single-quoted string.
echo $string | sed $'s/_/\t/g'
This does not rely on your terminal understanding the Control+V (insert next character literally) key binding—some may not. Also, because all the "invisible" characters can be represented literally, your solution can be copy-pasted without loss of information, and will be much more obvious/durable if you're using including this sed invocation in a script that other people might end up reading.
Also note that macOS's version of sed is the BSD version. GNU sed will interpret character escapes like \t in the replacement pattern just fine, and you wouldn't even need above workaround.
You can install GNU sed with MacPorts, and it should be made available as gsed, but Homebrew might supersede your system's sed depending on how you have your $PATH variable arranged.
Related
When I test bash script on my Mac, you know the \b is the DEL function:
$ echo -e "\\ 2\b"
\ 2
$ echo -e "\\ 2\b123"
\ 123
$ echo -e "\\ 2\b "
\
I found if the \b as the last character it will not work, see the first case.
But if there is space or other character following it, it will work.
EDIT
Sorry, \b not DEL, it is backspace, thanks #Evert
\b does not represent DEL, it represents backspace. This moves the Terminal cursor backward one space, but does not do anything to the character that's been backspaced over. If you print something after the backspace character, that'll be written over the previous character (effectively deleting it), but if you don't, it just remains on screen. If you want to really delete the character, send backspace+space+backspace (i.e. "\b \b").
BTW, echo isn't a good way to print sequences like this. Some versions convert escape sequences to the characters they represent, but some just print the escapes literally. I had to rewrite a bunch of my scripts when Mac OS X v10.5 came out, and had different behavior than I expected. Since then, I've always preferred printf for anything nontrivial. It's a bit more complicated than echo, because the first argument is treated as a format string, which is used to control how the rest of its arguments are printed. Also, it doesn't automatically add a newline at the end like echo does, so if you want that, you have to add it manually (with \n).
Finally, I'd use single-quotes for strings like this that include escape sequences, because in double-quotes some escape sequences get interpreted by the shell before being sent to the command (whether it's echo or printf). So here's how I'd do your second example:
printf '\\ 2\b123\n'
I wrote a little function, that "translates" a Windows path to a OSX path and opens it in the Finder. The function works perfectly with bash, but not with zsh (I use oh-my-zsh).
The problem is that it parses specific backslash combinations, for instance: \f, \a, \01, \02, \03, etc...
For example, this path string is the input:
"\60_Project\6038_Projekt_Part\05_development\assets\img\facebook"
After the translation function, the \f sequence (from img\facebook) is incorrectly translated as whitespace, producing the output:
"/60_Project/6038_Project_Part_developmentssets/img
acebook"
My goal is to just paste in a Windows path and not have to manually change anything.
How can I escape or quote a string with zsh, to get the result I want?
Here is the code I wrote:
function parsewinpath {
echo $1 | sed -e 's/\\/\//g'
}
function openwinpath {
echo "Opening..."
open $(parsewinpath "/Volumes/myvolume$1")
}
Usage:
openwinpath '\60_Project\6038_Project_Part\05_development\assets\img\facebook'
The result should be that the Finder opens:
/Volumes/myvolume/60_Project/6038_Project_Part/05_development/assets/img/facebook
You don't need parsewinpath at all. Just use parameter expansion to replace backslashes with forward slashes.
openwinpath /Volumes/myvolume${1//\\//}
The problem is that echo is trying to interpret escape sequences in the string as it prints it. Some versions of echo do this; some do it only if you pass the -e option; some print "-e" as part of their output; some do ... other random things. Basically, if you give echo something that contains escapes and/or starts with "-", there's no telling what it'll do.
Option 1: Use printf instead. It's a little more complicated, because you have to give it a format string as well as the actual string to be printed, but it's much more predictable. Oh, and double-quote variable references:
function parsewinpath {
printf '%s\n' "$1" | sed -e 's/\\/\//g'
}
Option 2: As #chepner pointed out, you can just skip echo, sed, and the whole mess, and use a parameter expansion to do the job:
function openwinpath {
echo "Opening..."
open "/Volumes/myvolume${1//\\//}"
}
Just escape each backslash with another backslash:
openwinpath '\\60_Project\\6038_Project_Part\\05_development\\assets\\img\\facebook'
Sorry, I know I'm 5 years late, but I thought an explanation of the problem's root and a workaround might be worth it for anyone else who ends up here:
Bash has a certain syntax. It interprets backslashes in a certain way. So you can't paste text with backslashes into the Terminal.
However, if you've copied the text to the clipboard, you may be able to circumvent bash's syntax by using a shell command to read the clipboard inside your script. So instead of using $1 to get your path from your script's argument, use pbpaste to read the clipboard directly.
So Im removing special characters from filenames and replacing with spaces. I have all working apart from files with single backslashes contained therein.
Note these files are created in the Finder on OS X
old_name="testing\this\folder"
new_name=$(echo $old_name | tr '<>:\\#%|?*' ' ');
This results in new_name being "testing hisolder"
How can I just removed the backslashes and not the preceding character?
This results in new_name being "testing hisolder"
This string looks like the result of echo -e "testing\this\folder", because \t and \f are actually replaced with the tabulation and form feed control characters.
Maybe you have an alias like alias echo='echo -e', or maybe the implementation of echo in your version of the shell interprets backslash escapes:
POSIX does not require support for any options, and says that the
behavior of ‘echo’ is implementation-defined if any STRING contains a
backslash or if the first argument is ‘-n’. Portable programs can use
the ‘printf’ command if they need to omit trailing newlines or output
control characters or backslashes.
(from the info page)
So you should use printf instead of echo in new software. In particular, echo $old_name should be replaced with printf %s "$old_name".
There is a good explanation in this discussion, for instance.
No need for printf
As #mklement0 suggested, you can avoid the pipe by means of the Bash here string:
tr '<>:\\#%|?*' ' ' <<<"$old_name"
Ruslan's excellent answer explains why your command may not be working for you and offers a robust, portable solution.
tl;dr:
You probably ran your code with sh rather than bash (even though on macOS sh is Bash in disguise), or you had shell option xpg_echo explicitly turned on.
Use printf instead of echo for portability.
In Bash, with the default options and using the echo builtin, your command should work as-is (except that you should double-quote $old_name for robustness), because echo by default does not expand escape sequences such as \t in its operands.
However, Bash's echo can be made to expand control-character escape sequences:
explicitly, by executing shopt -s xpg_echo
implicitly, if you run Bash as sh or with the --posix option (which, among other options and behavior changes, activates xpg_echo)
Thus, your symptom may have been caused by running your code from a script with shebang line #!/bin/sh, for instance.
However, if you're targeting sh, i.e., if you're writing a portable script, then echo should be avoided altogether for the very reason that its behavior differs across shells and platforms - see Ruslan's printf solution.
As an aside: perhaps a more robust approach to your tr command is a whitelisting approach: stating only the characters that are explicitly allowed in your result, and excluding other with the -C option:
old_name='testing\this\folder'
new_name=$(printf '%s' "$old_name" | tr -C '[:alnum:]_-' ' ')
That way, any characters that aren't either letters, numbers, _, or - are replaced with a space.
With Bash, you can use parameter expansion:
$ old_name="testing\this\folder"
$ new_name=${old_name//[<>:\\#%|?*]/ }
$ echo $new_name
testing this folder
For more, please refer to the Bash manual on shell parameter expansion.
I think your test case is missing proper escaping for \, so you're not really testing the case of a backslash contained in a string.
This worked for me:
old_name='testing\\this\\folder'
new_name=$(echo $old_name | tr '<>:\\#%|?*' ' ');
echo $new_name
# testing this folder
I need to identify whether my terminal prints colored output or not using bash scripts. Is there any direct shell command to do this? How can I do this?
My main goal is to identify whether the output matches with the default font color of terminal or not. If it's not matching, I should write an alert message in a text file.
Control characters are output characters as well, so you can detect their sequences similar to this answer.
if printf "\x1b[31mRed\x1b[0m" | grep -Pq "\\x1b\[[0-9;]+m"; then
echo colored
else
echo uncolored
fi
printf supports outputting control sequences. If you use echo, you'll need -e.
grep -q will suppress printing and just exit 0 (success) if it finds a match, and nonzero (failure) if it doesn't.
You'll need -P (PERL regular expressions) on grep for it to interpret the control sequence, because POSIX regular expressions don't support escape characters. Note the double-backslash in \\x1b, meaning you're letting grep handle the escape instead of your shell. Perl regular expressions are supported in GNU grep but seem not to be supported in BSD (including Mac OS X).
Some scripts only use control characters if they detect the input is tty-like, so you may want to use the script command to capture output including control characters directly to a file.
The way I do it is by searching for the
Escape Sequence, followed
by the color code, example
# red
awk '/\033\[31m/'
Example
Is there a \ESC or something I can put so echo command can interpret it?
Where is a list of these commands, like \t\n\r, etc?
If you're using bash, it's probably better to use that shell's so-called "ANSI-C Quoting". This lets you construct a string that you can pass to the echo command, which will simply print it.
For example, to print an ASCII ESC character:
echo $'\e'
or
echo -n $'\e'
if you don't want the trailing newline.
(The term "ANSI-C Quoting is a bit of a misnomer for several reasons. The C standard is currently produced by ISO, not ANSI, and the bash feature supports \e and \E to represent the Escape character, and \cX for control-X, features not in standard C. The handling of hex escapes is also a bit different.)
Even better, you can use the printf command, which also supports \e for the ESC character. printf is far more portable that echo. There are a number of different versions of the echo command, both as /bin/echo and as built-in commands in most shells. printf also exists in multiple versions, but the behavior across implementations is much more consistent. Code using printf is more likely to be portable to shells other than bash (or to older versions of bash) than code that depends on any of the more arcane features of bash's echo command, or of the GNU coreutils echo command.
Yes, you might have to pass the -e switch:
echo -e '\n\t\a'
you can find the list of interpreted escapes in echo manpage and info entry. This is for GNU coreutils echo, likely the one you are using:
If -e is in effect, the following sequences are recognized:
\\ backslash
\a alert (BEL)
\b backspace
\c produce no further output
\e escape
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\0NNN byte with octal value NNN (1 to 3 digits)
\xHH byte with hexadecimal value HH (1 to 2 digits)
Bash will replace /bin/echo with its own builtin, but all sequences above are interpreted.
Note that Posix compliance does not require this, so some shells will have partial or no support for the -e flag and escaping, namely Debian/Ubuntu Dash, which is the default shell on those platforms. You will have to invoke echo as /bin/echo to avoid calling the builtin and make sure your /bin/echo can handle escapes.
Use printf if you need to write portable code.