Is there a command to write text to a file without redirection, pipe or function?
This is a bit of an XY problem but fortunately you've explained your real problem so it's possible to give a meaningful answer.
Sure, there are commands that can write text to a file without relying on their environment to open the file. For example, sh
can do that: pass it the arguments -c
and echo text >filename
.
Note that this does meet the requirement of “without redirection” here, since the output of sh
is not redirected anywhere. There's a redirection inside the program that sh
runs, but that's ok, it's just an internal detail of how sh
works.
But does this solve your actual problem? Your actual problem is to write text to a file from a yad action. In order to resolve that, you need to determine what a yad action is. Unfortunately, the manual does not document this. All it says is
menu:STRING
Set popup menu for notification icon.
STRING
must be in formname1[!action1[!icon1]]|name2[!action2[!icon2]]...
. Empty name add separator to menu. Separator character for values (e.g.|
) sets with--separator
argument. Separator character for menu items (e.g.!
) sets with--item-separator
argument.
The action is a string, but a Unix command is a list of strings: a command name and its arguments. There are several plausible ways to turn a string into a command name and its arguments, including:
- Treating the string as a command name and calling it with no arguments. Since
echo foo
printsfoo
, rather than attempting to execute the programecho foo
, this is not what yad does. - Passing the string to a shell. Since
echo >filename
prints>filename
, rather than writing tofilename
, this is not what yad does. - Some custom string splitting. At this point, this is presumably what yad does, but depending on exactly how it does it, the solution to your problem can be different.
Looking at the source code, the action is passed to popup_menu_item_activate_cb
which calls the Glib function g_spawn_command_line_async
. This function splits the given string using g_shell_parse_argv
which has the following behavior, which is almost never what is desirable but can be worked around:
Parses a command line into an argument vector, in much the same way the shell would, but without many of the expansions the shell would perform (variable expansion, globs, operators, filename expansion, etc. are not supported). The results are defined to be the same as those you would get from a UNIX98 /bin/sh, as long as the input contains none of the unsupported shell expansions. If the input does contain such expansions, they are passed through literally.
So you can run a shell command by prefixing it with sh -c '
and terminating with '
. If you need a single quote inside the shell command, write '\''
. Alternatively, you can run a shell command by prefixing it with sh -c "
, terminating with "
, and adding a backslash before any of the characters "$\`
that appear in the command. Take care of the nested quoting since the action is itself quoted in the shell script that calls yad.
yad --notification \
--menu='Simple example!sh -c "echo sample text >text.txt"' \
--menu='Single-double-single quotes!sh -c "echo '\''Here you can put everything except single quotes literally: two spaces, a $dollar and a single'\''\'\'''\''quote.'\'' >text.txt"' \
--menu="Double-single-double quotes!sh -c 'echo \"Here punctuation is a bit tricky: two spaces, a \\\$dollar and a single'\\''quote.\"' >text.txt'"
If you wanna use features of shell, then run a shell:
yad --notification --command=quit --menu='Example!sh -c "echo sample >text.txt"'
A simple custom script will do, e.g. printto.py
:
#!/usr/bin/python
import sys
if len(sys.argv) == 3:
f = open(sys.argv[1], "w")
f.write(sys.argv[2])
f.close()
else :
print("usage: printto.py file message")
sys.exit(1)